Benny-Tang commited on
Commit
a1c1a89
·
verified ·
1 Parent(s): ddbd7d3

Create agents/swarm.py

Browse files
Files changed (1) hide show
  1. agents/swarm.py +192 -0
agents/swarm.py ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ python3 << 'PYEOF'
2
+ code = '''
3
+ import asyncio, json, re, os, requests
4
+ from bs4 import BeautifulSoup
5
+ from groq import AsyncGroq
6
+
7
+ MODEL = "llama-3.3-70b-versatile"
8
+
9
+ def _client():
10
+ return AsyncGroq(api_key=os.environ["GROQ_API_KEY"])
11
+
12
+ async def _llm(system, user, temperature=0.3):
13
+ r = await _client().chat.completions.create(
14
+ model=MODEL,
15
+ messages=[{"role":"system","content":system},{"role":"user","content":user}],
16
+ temperature=temperature, max_tokens=600)
17
+ return r.choices[0].message.content.strip()
18
+
19
+ async def _json(system, user):
20
+ raw = await _llm(system+"\\n\\nRespond ONLY with valid JSON. No markdown.", user)
21
+ clean = re.sub(r"```json|```","",raw).strip()
22
+ try:
23
+ return json.loads(clean)
24
+ except:
25
+ m = re.search(r"\\{.*\\}", clean, re.DOTALL)
26
+ if m:
27
+ try:
28
+ return json.loads(m.group())
29
+ except:
30
+ pass
31
+ return {"raw": raw}
32
+
33
+ def scrape_marine_traffic():
34
+ """
35
+ Scrapes MarineTraffic news for real-time shipping disruption signals.
36
+ Returns list of recent news headlines and summaries.
37
+ Falls back to simulated data if scraping fails.
38
+ """
39
+ try:
40
+ headers = {
41
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
42
+ }
43
+ url = "https://www.marinetraffic.com/en/ais/details/ships/straits"
44
+ news_items = []
45
+
46
+ # Try MarineTraffic blog for shipping news
47
+ blog_url = "https://www.marinetraffic.com/blog/"
48
+ r = requests.get(blog_url, headers=headers, timeout=8)
49
+ if r.status_code == 200:
50
+ soup = BeautifulSoup(r.text, "lxml")
51
+ articles = soup.find_all("article", limit=5)
52
+ for a in articles:
53
+ title = a.find("h2") or a.find("h3") or a.find("h1")
54
+ if title:
55
+ news_items.append({
56
+ "source": "MarineTraffic",
57
+ "headline": title.get_text(strip=True)[:200],
58
+ "type": "shipping_news"
59
+ })
60
+
61
+ # Also scrape Lloyd\'s List for Hormuz news
62
+ lloyds_url = "https://lloydslist.maritimeintelligence.informa.com/"
63
+ r2 = requests.get(lloyds_url, headers=headers, timeout=8)
64
+ if r2.status_code == 200:
65
+ soup2 = BeautifulSoup(r2.text, "lxml")
66
+ headlines = soup2.find_all(["h2","h3"], limit=5)
67
+ for h in headlines:
68
+ text = h.get_text(strip=True)
69
+ if len(text) > 20:
70
+ news_items.append({
71
+ "source": "LloydsList",
72
+ "headline": text[:200],
73
+ "type": "maritime_intelligence"
74
+ })
75
+
76
+ if news_items:
77
+ return {
78
+ "status": "live",
79
+ "source": "MarineTraffic + LloydsListI",
80
+ "items": news_items[:6],
81
+ "timestamp": __import__("datetime").datetime.utcnow().isoformat()
82
+ }
83
+ else:
84
+ raise Exception("No items scraped")
85
+
86
+ except Exception as e:
87
+ # Fallback: return simulated Hormuz disruption data
88
+ return {
89
+ "status": "simulated",
90
+ "source": "Aegis Internal Feed",
91
+ "note": f"Live scrape failed ({str(e)[:50]}), using crisis simulation data",
92
+ "items": [
93
+ {"source": "MarineTraffic", "headline": "3 tankers rerouted away from Strait of Hormuz amid escalating tensions", "type": "shipping_disruption"},
94
+ {"source": "MarineTraffic", "headline": "Iranian Revolutionary Guard patrol boats spotted near major shipping lanes", "type": "security_alert"},
95
+ {"source": "LloydsListI", "headline": "War risk insurance premiums surge 40% for Gulf vessels", "type": "financial_impact"},
96
+ {"source": "LloydsListI", "headline": "Major shipping lines suspend bookings through Hormuz indefinitely", "type": "operational_disruption"},
97
+ ],
98
+ "timestamp": __import__("datetime").datetime.utcnow().isoformat()
99
+ }
100
+
101
+ async def signal_agent(event):
102
+ # Enrich event with live MarineTraffic data
103
+ marine_data = scrape_marine_traffic()
104
+ event["marine_traffic"] = marine_data
105
+
106
+ r = await _json("""You are the Signal Agent for Aegis. Classify incoming signals.
107
+ You have access to live MarineTraffic shipping news.
108
+ Return JSON: severity(LOW|MEDIUM|HIGH|CRITICAL), signal_type, anomalies(list),
109
+ confidence(0-100), summary(1 sentence), shipping_alerts(list of strings from marine data).""",
110
+ f"Event: {json.dumps(event)}")
111
+ r["agent"] = "signal"
112
+ r["marine_data"] = marine_data
113
+ return r
114
+
115
+ async def intelligence_agent(signal, event):
116
+ r = await _json("""You are the Intelligence Agent for Aegis. Interpret signals for business risk.
117
+ Return JSON: root_cause, affected_regions(list), supply_chain_impact(LOW|MEDIUM|HIGH|SEVERE),
118
+ escalation_probability(0-100), geopolitical_context(1-2 sentences), time_to_impact_days(int).""",
119
+ f"Signal: {json.dumps(signal)}\\nEvent: {json.dumps(event)}")
120
+ r["agent"] = "intelligence"
121
+ return r
122
+
123
+ async def forecast_agent(intel, forecast_data):
124
+ r = await _json("""You are the Forecast Agent for Aegis. Interpret ML forecasts in business terms.
125
+ Return JSON: oil_outlook(string), price_trajectory(RISING|STABLE|FALLING|VOLATILE),
126
+ supply_risk_score(0-100), delay_probability(0-100), cost_impact_pct(float),
127
+ confidence_level(LOW|MEDIUM|HIGH), key_assumptions(list).""",
128
+ f"Intel: {json.dumps(intel)}\\nML summary: {json.dumps(forecast_data.get(\'summary\',{}))}")
129
+ r["agent"] = "forecast"
130
+ r["ml_summary"] = forecast_data.get("summary",{})
131
+ r["ml_forecast"] = forecast_data.get("forecast",[])[:14]
132
+ return r
133
+
134
+ async def simulation_agent(forecast, event):
135
+ r = await _json("""You are the Simulation Agent for Aegis. Run 3 supply chain scenarios.
136
+ Return JSON: scenarios(list of: name,probability,cost_impact_pct,lead_time_increase_days,description,mitigation_available).""",
137
+ f"Forecast: {json.dumps(forecast)}\\nEvent: {json.dumps(event)}")
138
+ r["agent"] = "simulation"
139
+ if "scenarios" not in r or not isinstance(r["scenarios"], list):
140
+ r["scenarios"] = []
141
+ return r
142
+
143
+ async def decision_agent(simulation, forecast, intel):
144
+ r = await _json("""You are the Decision Agent for Aegis — the final brain.
145
+ Return JSON: threat_level(LOW|MEDIUM|HIGH|CRITICAL),
146
+ recommended_actions(list of: priority,action,rationale,estimated_savings_usd,time_to_implement,risk),
147
+ executive_summary(2-3 sentences), do_nothing_cost_usd(int).""",
148
+ f"Scenarios: {json.dumps(simulation.get(\'scenarios\',[]))}\\nForecast: {json.dumps(forecast.get(\'ml_summary\',{}))}\\nIntel: {json.dumps(intel)}")
149
+ r["agent"] = "decision"
150
+ return r
151
+
152
+ async def alert_agent(decision, forecast):
153
+ r = await _json("""You are the Alert Agent for Aegis. Generate stakeholder alerts.
154
+ Return JSON: slack_message(string,max 200 chars), email_subject, email_body(3-4 sentences),
155
+ severity_emoji, notification_channels(list).""",
156
+ f"Decision: {json.dumps(decision)}\\nForecast: {json.dumps(forecast.get(\'ml_summary\',{}))}")
157
+ r["agent"] = "alert"
158
+ return r
159
+
160
+ async def execution_agent(decision):
161
+ r = await _json("""You are the Execution Agent for Aegis. Determine workflows to trigger.
162
+ Return JSON: triggered_workflows(list of: system,action,api_endpoint,payload_summary,status,requires_human_approval),
163
+ autonomous_actions_count(int), pending_approvals_count(int), execution_summary(1 sentence).""",
164
+ f"Actions: {json.dumps(decision.get(\'recommended_actions\',[])[:3])}")
165
+ r["agent"] = "execution"
166
+ return r
167
+
168
+ async def run_aegis_pipeline(event, forecast_data):
169
+ results = {"event": event, "agents": {}}
170
+ sig = await signal_agent(event)
171
+ results["agents"]["signal"] = sig
172
+ intel = await intelligence_agent(sig, event)
173
+ results["agents"]["intelligence"] = intel
174
+ fore = await forecast_agent(intel, forecast_data)
175
+ results["agents"]["forecast"] = fore
176
+ sim = await simulation_agent(fore, event)
177
+ results["agents"]["simulation"] = sim
178
+ dec = await decision_agent(sim, fore, intel)
179
+ results["agents"]["decision"] = dec
180
+ alert = await alert_agent(dec, fore)
181
+ results["agents"]["alert"] = alert
182
+ exe = await execution_agent(dec)
183
+ results["agents"]["execution"] = exe
184
+ print("Pipeline complete")
185
+ return results
186
+ '''
187
+ with open("/opt/aegis/agents/swarm.py","w") as f:
188
+ f.write(code)
189
+ print("swarm.py written OK")
190
+ PYEOF
191
+
192
+ ✅ Should print: swarm.py written OK