feat: integrate MinIO-backed user filesystem
This commit is contained in:
@ -14,7 +14,7 @@ from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
import json
|
||||
from pathlib import Path
|
||||
from pathlib import Path, PurePosixPath
|
||||
from typing import Any, Iterable
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ MAX_READ_CHARS = 120_000
|
||||
MAX_SEARCH_RESULTS = 200
|
||||
MAX_SEARCH_FILE_BYTES = 2_000_000
|
||||
MAX_SEARCH_FILES = 5_000
|
||||
USER_FILE_VIRTUAL_ROOTS = {"uploads", "outputs", "shared", "tasks"}
|
||||
SKIP_DIR_NAMES = {
|
||||
".git",
|
||||
".hg",
|
||||
@ -161,9 +162,28 @@ def _workspace_root(workspace: str | None) -> Path:
|
||||
return root
|
||||
|
||||
|
||||
def _virtual_user_file_error(user_path: str | None) -> str | None:
|
||||
raw = str(user_path or ".").replace("\\", "/").strip()
|
||||
if not raw or raw in {".", "./"}:
|
||||
return None
|
||||
try:
|
||||
parts = [part for part in PurePosixPath(raw.strip("/")).parts if part not in ("", ".")]
|
||||
except TypeError:
|
||||
return None
|
||||
if parts and parts[0] in USER_FILE_VIRTUAL_ROOTS:
|
||||
return (
|
||||
f"{user_path} is a personal agent file system path, not a workspace path. "
|
||||
"Use user_files_read or user_files_copy_to_workspace for reads; use "
|
||||
"user_files_write for shared/tasks files or user_files_publish_output for outputs."
|
||||
)
|
||||
return None
|
||||
|
||||
|
||||
def _resolve_existing_path(workspace: str | None, user_path: str | None) -> tuple[Path, Path]:
|
||||
"""Resolve a user path and ensure the real target stays inside workspace."""
|
||||
|
||||
if error := _virtual_user_file_error(user_path):
|
||||
raise WorkspacePathError(error)
|
||||
root = _workspace_root(workspace)
|
||||
raw_path = Path(user_path or ".").expanduser()
|
||||
candidate = raw_path if raw_path.is_absolute() else root / raw_path
|
||||
@ -178,6 +198,8 @@ def _resolve_existing_path(workspace: str | None, user_path: str | None) -> tupl
|
||||
|
||||
|
||||
def _resolve_writable_path(workspace: str | None, user_path: str | None) -> tuple[Path, Path]:
|
||||
if error := _virtual_user_file_error(user_path):
|
||||
raise WorkspacePathError(error)
|
||||
root = _workspace_root(workspace)
|
||||
if not user_path or not str(user_path).strip():
|
||||
raise WorkspacePathError("path is required")
|
||||
|
||||
Reference in New Issue
Block a user