PYAE1994 commited on
Commit
5035a22
Β·
verified Β·
1 Parent(s): cbb4d33

God Mode+ v3 fix: agents/deploy_agent.py

Browse files
Files changed (1) hide show
  1. agents/deploy_agent.py +152 -78
agents/deploy_agent.py CHANGED
@@ -1,24 +1,19 @@
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,76 +21,155 @@ 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."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
  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}"