""" DeployAgent — Automated deployments to Vercel, HF Spaces, GitHub Pages """ import json import os from typing import Dict import httpx import structlog from .base_agent import BaseAgent log = structlog.get_logger() DEPLOY_SYSTEM = """You are a deployment engineer expert in: - Vercel deployments (Next.js, React, API routes) - HuggingFace Spaces (Docker, Gradio, Streamlit) - GitHub Pages (static sites) - Docker containerization - Environment variable management Generate precise deployment configs and commands. """ class DeployAgent(BaseAgent): def __init__(self, ws_manager=None, ai_router=None): super().__init__("DeployAgent", ws_manager, ai_router) async def run(self, task: str, context: Dict = {}, **kwargs) -> str: session_id = kwargs.get("session_id", "") task_id = kwargs.get("task_id", "") await self.emit(task_id, "agent_start", {"agent": "DeployAgent", "task": task[:80]}, session_id) task_lower = task.lower() if "vercel" in task_lower: return await self._deploy_vercel_guide(task, task_id, session_id) elif "huggingface" in task_lower or "hf" in task_lower or "space" in task_lower: return await self._deploy_hf_guide(task, task_id, session_id) elif "docker" in task_lower: return await self._generate_dockerfile(task, task_id, session_id) else: return await self._deploy_general(task, task_id, session_id) async def _deploy_vercel_guide(self, task: str, task_id: str, session_id: str) -> str: messages = [ {"role": "system", "content": DEPLOY_SYSTEM}, {"role": "user", "content": ( f"Generate complete Vercel deployment guide for: {task}\n\n" f"Include:\n1. vercel.json config\n2. Environment variables needed\n" f"3. Build commands\n4. Step-by-step deployment instructions" )}, ] result = await self.llm(messages, task_id=task_id, session_id=session_id, temperature=0.2) await self.emit(task_id, "deploy_plan_ready", {"platform": "vercel"}, session_id) return result async def _deploy_hf_guide(self, task: str, task_id: str, session_id: str) -> str: messages = [ {"role": "system", "content": DEPLOY_SYSTEM}, {"role": "user", "content": ( f"Generate HuggingFace Space deployment for: {task}\n\n" f"Include:\n1. Dockerfile\n2. README.md with YAML header\n" f"3. Requirements/dependencies\n4. Space configuration" )}, ] result = await self.llm(messages, task_id=task_id, session_id=session_id, temperature=0.2) await self.emit(task_id, "deploy_plan_ready", {"platform": "huggingface"}, session_id) return result async def _generate_dockerfile(self, task: str, task_id: str, session_id: str) -> str: messages = [ {"role": "system", "content": DEPLOY_SYSTEM}, {"role": "user", "content": f"Generate production Dockerfile for: {task}\nInclude multi-stage build, security best practices, health check."}, ] return await self.llm(messages, task_id=task_id, session_id=session_id, temperature=0.1) async def _deploy_general(self, task: str, task_id: str, session_id: str) -> str: messages = [ {"role": "system", "content": DEPLOY_SYSTEM}, {"role": "user", "content": f"Create deployment plan for: {task}\n\nInclude platform recommendation, config files, and step-by-step guide."}, ] return await self.llm(messages, task_id=task_id, session_id=session_id) async def check_vercel_deployments(self) -> str: """Check recent Vercel deployments.""" token = os.environ.get("VERCEL_TOKEN", "") if not token: return "⚠️ VERCEL_TOKEN not set." try: async with httpx.AsyncClient(timeout=15) as client: resp = await client.get( "https://api.vercel.com/v6/deployments?limit=5", headers={"Authorization": f"Bearer {token}"} ) if resp.status_code == 200: deps = resp.json().get("deployments", []) lines = [f"- {d.get('name')} → {d.get('state')} ({d.get('url', '')})" for d in deps[:5]] return "🚀 **Recent Vercel Deployments:**\n\n" + "\n".join(lines) except Exception as e: return f"❌ Vercel error: {e}" return "No deployments found."