"""Shared path resolution for thread virtual paths (e.g. mnt/user-data/outputs/...).""" from pathlib import Path from fastapi import HTTPException from deerflow.config.paths import get_paths from deerflow.runtime.user_context import get_effective_user_id def resolve_thread_virtual_path(thread_id: str, virtual_path: str, user_id: str | None = None) -> Path: """Resolve a virtual path to the actual filesystem path under thread user-data. Args: thread_id: The thread ID. virtual_path: The virtual path as seen inside the sandbox (e.g., /mnt/user-data/outputs/file.txt). user_id: The user whose storage to resolve under. Defaults to the effective user when not given; callers acting on behalf of a specific owner (e.g. trusted internal callers) pass it explicitly. Returns: The resolved filesystem path. Raises: HTTPException: If the path is invalid or outside allowed directories. """ try: return get_paths().resolve_virtual_path(thread_id, virtual_path, user_id=user_id or get_effective_user_id()) except ValueError as e: status = 403 if "traversal" in str(e) else 400 raise HTTPException(status_code=status, detail=str(e))