PYAE1994 commited on
Commit
26ad3b3
·
verified ·
1 Parent(s): 7ee2111

Fix: update agents/deploy_agent.py

Browse files
Files changed (1) hide show
  1. agents/deploy_agent.py +78 -152
agents/deploy_agent.py CHANGED
@@ -1,19 +1,24 @@
1
  """
2
- DeployAgent — Real deployments to Vercel, HuggingFace, GitHub
3
- Uses actual APIs (no mock/fake responses)
4
  """
5
  import json
6
  import os
7
- import structlog
8
- from typing import Dict, Optional
9
  import httpx
 
10
  from .base_agent import BaseAgent
11
 
12
  log = structlog.get_logger()
13
 
14
- VERCEL_TOKEN = os.environ.get("VERCEL_TOKEN", "")
15
- HF_TOKEN = os.environ.get("HF_TOKEN", "")
16
- GITHUB_TOKEN = os.environ.get("GITHUB_TOKEN", "")
 
 
 
 
 
 
17
 
18
 
19
  class DeployAgent(BaseAgent):
@@ -21,155 +26,76 @@ class DeployAgent(BaseAgent):
21
  super().__init__("DeployAgent", ws_manager, ai_router)
22
 
23
  async def run(self, task: str, context: Dict = {}, **kwargs) -> str:
24
- session_id = kwargs.get("session_id", context.get("session_id", ""))
25
- task_id = kwargs.get("task_id", context.get("task_id", ""))
26
- task_lower = task.lower()
27
 
28
- await self.emit(task_id, "deploy_started", {"task": task[:100]}, session_id)
29
 
 
30
  if "vercel" in task_lower:
31
- return await self.deploy_vercel(context, task_id, session_id)
32
- elif "hf" in task_lower or "huggingface" in task_lower or "space" in task_lower:
33
- return await self.deploy_hf(context, task_id, session_id)
34
- elif "github" in task_lower:
35
- return await self.push_github(context, task_id, session_id)
36
  else:
37
- return await self.deploy_vercel(context, task_id, session_id)
38
-
39
- # ─── Vercel Deploy ────────────────────────────────────────────────────────
40
-
41
- async def deploy_vercel(self, context: Dict, task_id: str, session_id: str) -> str:
42
- if not VERCEL_TOKEN:
43
- return " VERCEL_TOKEN not set cannot deploy to Vercel"
44
-
45
- project_name = context.get("project_name", "god-mode-frontend")
46
- files = context.get("files", {})
47
-
48
- if not files:
49
- return " No files provided for Vercel deployment"
50
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  try:
52
- payload = {
53
- "name": project_name,
54
- "files": [
55
- {"file": path, "data": content}
56
- for path, content in files.items()
57
- ],
58
- "projectSettings": {"framework": "nextjs"},
59
- }
60
- async with httpx.AsyncClient(timeout=60.0) as client:
61
- resp = await client.post(
62
- "https://api.vercel.com/v13/deployments",
63
- headers={
64
- "Authorization": f"Bearer {VERCEL_TOKEN}",
65
- "Content-Type": "application/json",
66
- },
67
- json=payload,
68
  )
69
- resp.raise_for_status()
70
- data = resp.json()
71
- url = data.get("url", "")
72
- uid = data.get("uid", "")
73
- await self.emit(task_id, "deploy_completed", {
74
- "platform": "vercel", "url": url, "uid": uid
75
- }, session_id)
76
- return f"✅ Deployed to Vercel: https://{url}"
77
  except Exception as e:
78
- log.error("Vercel deploy failed", error=str(e))
79
- return f" Vercel deploy error: {str(e)}"
80
-
81
- # ─── HF Space Update ──────────────────────────────────────────────────────
82
-
83
- async def deploy_hf(self, context: Dict, task_id: str, session_id: str) -> str:
84
- if not HF_TOKEN:
85
- return "❌ HF_TOKEN not set — cannot deploy to HuggingFace"
86
-
87
- repo_id = context.get("repo_id", "")
88
- files = context.get("files", {})
89
-
90
- if not repo_id:
91
- return "❌ repo_id required for HF Space deployment"
92
-
93
- results = []
94
- async with httpx.AsyncClient(timeout=60.0) as client:
95
- for path, content in files.items():
96
- try:
97
- resp = await client.put(
98
- f"https://huggingface.co/api/spaces/{repo_id}/upload/{path}",
99
- headers={
100
- "Authorization": f"Bearer {HF_TOKEN}",
101
- "Content-Type": "application/octet-stream",
102
- },
103
- content=content.encode() if isinstance(content, str) else content,
104
- )
105
- resp.raise_for_status()
106
- results.append(f"✅ {path}")
107
- except Exception as e:
108
- results.append(f"❌ {path}: {str(e)}")
109
-
110
- summary = "\n".join(results)
111
- await self.emit(task_id, "deploy_completed", {
112
- "platform": "huggingface", "repo_id": repo_id, "files": len(files)
113
- }, session_id)
114
- return f"**HuggingFace Space Deploy** ({repo_id}):\n{summary}"
115
-
116
- # ─── GitHub Push ──────────────────────────────────────────────────────────
117
-
118
- async def push_github(self, context: Dict, task_id: str, session_id: str) -> str:
119
- if not GITHUB_TOKEN:
120
- return "❌ GITHUB_TOKEN not set — cannot push to GitHub"
121
-
122
- repo = context.get("repo", "")
123
- files = context.get("files", {})
124
- message = context.get("commit_message", "God Agent automated commit")
125
- branch = context.get("branch", "main")
126
-
127
- if not repo or not files:
128
- return "❌ repo and files required for GitHub push"
129
-
130
- results = []
131
- async with httpx.AsyncClient(timeout=30.0) as client:
132
- headers = {
133
- "Authorization": f"token {GITHUB_TOKEN}",
134
- "Accept": "application/vnd.github.v3+json",
135
- }
136
- for path, content in files.items():
137
- try:
138
- import base64
139
- encoded = base64.b64encode(
140
- content.encode() if isinstance(content, str) else content
141
- ).decode()
142
-
143
- # Check if file exists (get SHA)
144
- sha = None
145
- get_resp = await client.get(
146
- f"https://api.github.com/repos/{repo}/contents/{path}",
147
- headers=headers,
148
- params={"ref": branch},
149
- )
150
- if get_resp.status_code == 200:
151
- sha = get_resp.json().get("sha")
152
-
153
- payload: Dict = {
154
- "message": message,
155
- "content": encoded,
156
- "branch": branch,
157
- }
158
- if sha:
159
- payload["sha"] = sha
160
-
161
- put_resp = await client.put(
162
- f"https://api.github.com/repos/{repo}/contents/{path}",
163
- headers=headers,
164
- json=payload,
165
- )
166
- put_resp.raise_for_status()
167
- results.append(f"✅ {path}")
168
- except Exception as e:
169
- results.append(f"❌ {path}: {str(e)}")
170
-
171
- summary = "\n".join(results)
172
- await self.emit(task_id, "deploy_completed", {
173
- "platform": "github", "repo": repo, "files": len(files)
174
- }, session_id)
175
- return f"**GitHub Push** ({repo}/{branch}):\n{summary}"
 
1
  """
2
+ DeployAgent — Automated deployments to Vercel, HF Spaces, GitHub Pages
 
3
  """
4
  import json
5
  import os
6
+ from typing import Dict
 
7
  import httpx
8
+ import structlog
9
  from .base_agent import BaseAgent
10
 
11
  log = structlog.get_logger()
12
 
13
+ DEPLOY_SYSTEM = """You are a deployment engineer expert in:
14
+ - Vercel deployments (Next.js, React, API routes)
15
+ - HuggingFace Spaces (Docker, Gradio, Streamlit)
16
+ - GitHub Pages (static sites)
17
+ - Docker containerization
18
+ - Environment variable management
19
+
20
+ Generate precise deployment configs and commands.
21
+ """
22
 
23
 
24
  class DeployAgent(BaseAgent):
 
26
  super().__init__("DeployAgent", ws_manager, ai_router)
27
 
28
  async def run(self, task: str, context: Dict = {}, **kwargs) -> str:
29
+ session_id = kwargs.get("session_id", "")
30
+ task_id = kwargs.get("task_id", "")
 
31
 
32
+ await self.emit(task_id, "agent_start", {"agent": "DeployAgent", "task": task[:80]}, session_id)
33
 
34
+ task_lower = task.lower()
35
  if "vercel" in task_lower:
36
+ return await self._deploy_vercel_guide(task, task_id, session_id)
37
+ elif "huggingface" in task_lower or "hf" in task_lower or "space" in task_lower:
38
+ return await self._deploy_hf_guide(task, task_id, session_id)
39
+ elif "docker" in task_lower:
40
+ return await self._generate_dockerfile(task, task_id, session_id)
41
  else:
42
+ return await self._deploy_general(task, task_id, session_id)
43
+
44
+ async def _deploy_vercel_guide(self, task: str, task_id: str, session_id: str) -> str:
45
+ messages = [
46
+ {"role": "system", "content": DEPLOY_SYSTEM},
47
+ {"role": "user", "content": (
48
+ f"Generate complete Vercel deployment guide for: {task}\n\n"
49
+ f"Include:\n1. vercel.json config\n2. Environment variables needed\n"
50
+ f"3. Build commands\n4. Step-by-step deployment instructions"
51
+ )},
52
+ ]
53
+ result = await self.llm(messages, task_id=task_id, session_id=session_id, temperature=0.2)
54
+ await self.emit(task_id, "deploy_plan_ready", {"platform": "vercel"}, session_id)
55
+ return result
56
+
57
+ async def _deploy_hf_guide(self, task: str, task_id: str, session_id: str) -> str:
58
+ messages = [
59
+ {"role": "system", "content": DEPLOY_SYSTEM},
60
+ {"role": "user", "content": (
61
+ f"Generate HuggingFace Space deployment for: {task}\n\n"
62
+ f"Include:\n1. Dockerfile\n2. README.md with YAML header\n"
63
+ f"3. Requirements/dependencies\n4. Space configuration"
64
+ )},
65
+ ]
66
+ result = await self.llm(messages, task_id=task_id, session_id=session_id, temperature=0.2)
67
+ await self.emit(task_id, "deploy_plan_ready", {"platform": "huggingface"}, session_id)
68
+ return result
69
+
70
+ async def _generate_dockerfile(self, task: str, task_id: str, session_id: str) -> str:
71
+ messages = [
72
+ {"role": "system", "content": DEPLOY_SYSTEM},
73
+ {"role": "user", "content": f"Generate production Dockerfile for: {task}\nInclude multi-stage build, security best practices, health check."},
74
+ ]
75
+ return await self.llm(messages, task_id=task_id, session_id=session_id, temperature=0.1)
76
+
77
+ async def _deploy_general(self, task: str, task_id: str, session_id: str) -> str:
78
+ messages = [
79
+ {"role": "system", "content": DEPLOY_SYSTEM},
80
+ {"role": "user", "content": f"Create deployment plan for: {task}\n\nInclude platform recommendation, config files, and step-by-step guide."},
81
+ ]
82
+ return await self.llm(messages, task_id=task_id, session_id=session_id)
83
+
84
+ async def check_vercel_deployments(self) -> str:
85
+ """Check recent Vercel deployments."""
86
+ token = os.environ.get("VERCEL_TOKEN", "")
87
+ if not token:
88
+ return "⚠️ VERCEL_TOKEN not set."
89
  try:
90
+ async with httpx.AsyncClient(timeout=15) as client:
91
+ resp = await client.get(
92
+ "https://api.vercel.com/v6/deployments?limit=5",
93
+ headers={"Authorization": f"Bearer {token}"}
 
 
 
 
 
 
 
 
 
 
 
 
94
  )
95
+ if resp.status_code == 200:
96
+ deps = resp.json().get("deployments", [])
97
+ lines = [f"- {d.get('name')} → {d.get('state')} ({d.get('url', '')})" for d in deps[:5]]
98
+ return "🚀 **Recent Vercel Deployments:**\n\n" + "\n".join(lines)
 
 
 
 
99
  except Exception as e:
100
+ return f" Vercel error: {e}"
101
+ return "No deployments found."