qwen_agent/utils/daytona_file_fetcher.py
朱潮 b4f8bb2935 refactor: replace mcp_resources API with direct /robots/ static file access
- Remove routes/mcp_resources.py (ui:// URI resolver endpoint)
- Frontend now directly accesses /robots/{bot_id}/skills/{server}/apps/{resource}.html
- Add Daytona fallback middleware to fetch files from sandbox on 404
- Add utils/daytona_file_fetcher.py for on-demand single file download

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-20 18:58:58 +08:00

52 lines
1.7 KiB
Python

"""On-demand single file fetcher from Daytona sandbox."""
import logging
from pathlib import Path
from utils.settings import DAYTONA_ENABLED, DAYTONA_API_KEY, DAYTONA_SERVER_URL
logger = logging.getLogger('app')
REMOTE_WORKSPACE_ROOT = "/workspace"
def fetch_file_from_daytona(bot_id: str, relative_path: str, local_path: Path) -> bool:
"""Fetch a single file from the Daytona sandbox and save it locally.
Args:
bot_id: The bot ID (sandbox is named "bot-{bot_id}")
relative_path: Path relative to the bot's workspace root
local_path: Local filesystem path where the file should be saved
Returns:
True if the file was successfully fetched and saved, False otherwise
"""
if not (DAYTONA_ENABLED and DAYTONA_API_KEY and DAYTONA_SERVER_URL):
return False
try:
from daytona import Daytona, DaytonaConfig
config = DaytonaConfig(api_key=DAYTONA_API_KEY, api_url=DAYTONA_SERVER_URL)
client = Daytona(config)
sandbox_name = f"bot-{bot_id}"
sandbox = client.get(sandbox_name)
if sandbox.state not in ("Started", "Creating"):
logger.warning(f"Sandbox {sandbox_name} not running (state={sandbox.state})")
return False
remote_path = f"{REMOTE_WORKSPACE_ROOT}/{relative_path}"
content = sandbox.fs.download_file(remote_path)
local_path.parent.mkdir(parents=True, exist_ok=True)
local_path.write_bytes(content)
logger.info(f"Fetched file from Daytona: {remote_path} -> {local_path}")
return True
except Exception as e:
logger.warning(f"Failed to fetch file from Daytona for bot {bot_id}: {e}")
return False