fix backup and file limit

frdel committed Feb 6, 2026 at 14:11 UTC 65607a36fcd460c775f59dfca01adb09d7f9e9cf
7 files changed +31 -16
python/api/backup_create.py
+1 -1
@@ -17,7 +17,7 @@ class BackupCreate(ApiHandler):
17 # Get input parameters
18 include_patterns = input.get("include_patterns", [])
19 exclude_patterns = input.get("exclude_patterns", [])
20 - include_hidden = input.get("include_hidden", False)
20 + include_hidden = input.get("include_hidden", True)
21 backup_name = input.get("backup_name", "agent-zero-backup")
22
23 # Support legacy string patterns format for backward compatibility
python/api/backup_inspect.py
+1 -1
@@ -37,7 +37,7 @@ class BackupInspect(ApiHandler):
37 "backup_name": metadata.get("backup_name", ""),
38 "total_files": metadata.get("total_files", len(metadata.get("files", []))),
39 "backup_size": metadata.get("backup_size", 0),
40 - "include_hidden": metadata.get("include_hidden", False),
40 + "include_hidden": metadata.get("include_hidden", True),
41 "files_in_archive": metadata.get("files_in_archive", []),
42 "checksums": {} # Will be added if needed
43 }
python/api/backup_preview_grouped.py
+1 -1
@@ -17,7 +17,7 @@ class BackupPreviewGrouped(ApiHandler):
17 # Get input parameters
18 include_patterns = input.get("include_patterns", [])
19 exclude_patterns = input.get("exclude_patterns", [])
20 - include_hidden = input.get("include_hidden", False)
20 + include_hidden = input.get("include_hidden", True)
21 max_depth = input.get("max_depth", 3)
22 search_filter = input.get("search_filter", "")
23
python/api/backup_test.py
+1 -1
@@ -16,7 +16,7 @@ class BackupTest(ApiHandler):
16 # Get input parameters
17 include_patterns = input.get("include_patterns", [])
18 exclude_patterns = input.get("exclude_patterns", [])
19 - include_hidden = input.get("include_hidden", False)
19 + include_hidden = input.get("include_hidden", True)
20 max_files = input.get("max_files", 1000)
21
22 # Support legacy string patterns format for backward compatibility
python/helpers/backup.py
+6 -6
@@ -43,7 +43,7 @@ class BackupService:
43
44 return {
45 "backup_name": f"agent-zero-backup-{timestamp[:10]}",
46 - "include_hidden": False,
46 + "include_hidden": True,
47 "include_patterns": include_patterns,
48 "exclude_patterns": exclude_patterns,
49 "backup_config": {
@@ -64,8 +64,8 @@ class BackupService:
64 # All persistent user data is now centralized in /usr for easier backup and restore
65 {agent_root}/usr/**
66
67 -# Explicitly include .env
68 -{agent_root}/usr/.env
67 +# Root folder
68 +/root/**
69 """
70
71 def _get_agent_zero_version(self) -> str:
@@ -247,7 +247,7 @@ class BackupService:
247 """Test backup patterns and return list of matched files"""
248 include_patterns = metadata.get("include_patterns", [])
249 exclude_patterns = metadata.get("exclude_patterns", [])
250 - include_hidden = metadata.get("include_hidden", False)
250 + include_hidden = metadata.get("include_hidden", True)
251
252 # Convert to patterns string for pathspec
253 patterns_string = self._patterns_to_string(include_patterns, exclude_patterns)
@@ -332,7 +332,7 @@ class BackupService:
332 self,
333 include_patterns: List[str],
334 exclude_patterns: List[str],
335 - include_hidden: bool = False,
335 + include_hidden: bool = True,
336 backup_name: str = "agent-zero-backup"
337 ) -> str:
338 """Create backup archive and return path to created file"""
@@ -807,7 +807,7 @@ class BackupService:
807 # Use user-edited patterns for what to clean
808 user_include_patterns = user_metadata.get("include_patterns", [])
809 user_exclude_patterns = user_metadata.get("exclude_patterns", [])
810 - include_hidden = user_metadata.get("include_hidden", False)
810 + include_hidden = user_metadata.get("include_hidden", True)
811
812 if not user_include_patterns:
813 return []
run_ui.py
+11 -1
@@ -10,6 +10,7 @@ import threading
10 import uvicorn
11 from flask import Flask, request, Response, session, redirect, url_for, render_template_string
12 from werkzeug.wrappers.response import Response as BaseResponse
13 +from werkzeug.wrappers.request import Request as WerkzeugRequest
14
15 import initialize
16 from python.helpers import files, git, mcp_server, fasta2a_server, settings as settings_helper
@@ -43,12 +44,21 @@ if hasattr(time, 'tzset'):
44 # initialize the internal Flask server
45 webapp = Flask("app", static_folder=get_abs_path("./webui"), static_url_path="/")
46 webapp.secret_key = os.getenv("FLASK_SECRET_KEY") or secrets.token_hex(32)
47 +
48 +UPLOAD_LIMIT_BYTES = 5 * 1024 * 1024 * 1024
49 +
50 +# Werkzeug's default max_form_memory_size is 500_000 bytes which can trigger 413 for multipart requests
51 +# with larger non-file fields. Raise it to match our intended upload limit.
52 +WerkzeugRequest.max_form_memory_size = UPLOAD_LIMIT_BYTES
53 +
54 webapp.config.update(
55 JSON_SORT_KEYS=False,
56 SESSION_COOKIE_NAME="session_" + runtime.get_runtime_id(), # bind the session cookie name to runtime id to prevent session collision on same host
57 SESSION_COOKIE_SAMESITE="Strict",
58 SESSION_PERMANENT=True,
51 - PERMANENT_SESSION_LIFETIME=timedelta(days=1)
59 + PERMANENT_SESSION_LIFETIME=timedelta(days=1),
60 + MAX_CONTENT_LENGTH=int(os.getenv("FLASK_MAX_CONTENT_LENGTH", str(UPLOAD_LIMIT_BYTES))),
61 + MAX_FORM_MEMORY_SIZE=int(os.getenv("FLASK_MAX_FORM_MEMORY_SIZE", str(UPLOAD_LIMIT_BYTES))),
62 )
63
64 lock = threading.RLock()
webui/components/settings/backup/backup-store.js
+10 -5
@@ -114,7 +114,7 @@ const model = {
114
115 return {
116 backup_name: `agent-zero-backup-${timestamp.slice(0, 10)}`,
117 - include_hidden: false,
117 + include_hidden: true,
118 include_patterns: include_patterns,
119 exclude_patterns: exclude_patterns,
120 backup_config: {
@@ -130,7 +130,7 @@ const model = {
130 // Fallback patterns (will be overridden by backend on first use)
131 return {
132 backup_name: `agent-zero-backup-${timestamp.slice(0, 10)}`,
133 - include_hidden: false,
133 + include_hidden: true,
134 include_patterns: [
135 // These will be replaced with resolved absolute paths by backend
136 "# Loading default patterns from backend..."
@@ -245,7 +245,7 @@ const model = {
245 // Get grouped preview for better UX
246 const response = await sendJsonData("backup_preview_grouped", {
247 patterns: patternsString,
248 - include_hidden: metadata.include_hidden || false,
248 + include_hidden: metadata.include_hidden ?? true,
249 max_depth: 3,
250 search_filter: this.fileSearchFilter
251 });
@@ -391,6 +391,7 @@ const model = {
391
392 try {
393 this.loading = true;
394 + this.loadingMessage = 'Creating backup...';
395 this.error = '';
396 this.clearFileOperations();
397 this.addFileOperation('Starting backup creation...');
@@ -404,7 +405,7 @@ const model = {
405 body: JSON.stringify({
406 include_patterns: metadata.include_patterns,
407 exclude_patterns: metadata.exclude_patterns,
407 - include_hidden: metadata.include_hidden || false,
408 + include_hidden: metadata.include_hidden ?? true,
409 backup_name: metadata.backup_name
410 })
411 });
@@ -500,6 +501,7 @@ const model = {
501 try {
502 this.loading = true;
503 this.loadingMessage = 'Performing dry run...';
504 + this.error = '';
505 this.clearFileOperations();
506 this.addFileOperation('Starting backup dry run...');
507
@@ -508,7 +510,7 @@ const model = {
510
511 const response = await sendJsonData("backup_test", {
512 patterns: patternsString,
511 - include_hidden: metadata.include_hidden || false,
513 + include_hidden: metadata.include_hidden ?? true,
514 max_files: 10000
515 });
516
@@ -540,6 +542,8 @@ const model = {
542 try {
543 this.loading = true;
544 this.loadingMessage = 'Performing restore dry run...';
545 + this.error = '';
546 + this.restoreResult = null;
547 this.clearFileOperations();
548 this.addFileOperation('Starting restore dry run...');
549
@@ -692,6 +696,7 @@ const model = {
696 this.loading = true;
697 this.loadingMessage = 'Restoring files...';
698 this.error = '';
699 + this.restoreResult = null;
700 this.clearFileOperations();
701 this.addFileOperation('Starting file restoration...');
702