File size: 4,584 Bytes
02117ee
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
"""
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."