-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbot.py
More file actions
223 lines (184 loc) · 9.68 KB
/
bot.py
File metadata and controls
223 lines (184 loc) · 9.68 KB
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
"""
examples/social_agent/bot.py
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
AgentX social media automation agent.
The agent:
1. Reads a stream of mock tweets about Solana / crypto
2. Classifies each tweet (topic + sentiment)
3. For relevant tweets, generates an on-brand AI reply
4. Posts the reply (dry-run by default; set DRY_RUN=false to post live)
Run: python examples/social_agent/bot.py [--count 10] [--live]
"""
import os
import sys
import time
import json
import random
import argparse
from dataclasses import dataclass
from datetime import datetime, timedelta
from dotenv import load_dotenv
from rich.console import Console
from rich.table import Table
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "..", "..", "AgentX-Core", "src"))
from agentx import Agent, Tool
load_dotenv()
console = Console()
# ---------------------------------------------------------------------------
# Mock tweet stream
# ---------------------------------------------------------------------------
MOCK_TWEETS = [
{"id": "1001", "user": "@defi_chad", "text": "Solana is absolutely flying today. SOL up 4% and Jito vaults yielding 8% APY. Bullish af 🚀", "likes": 342, "retweets": 87},
{"id": "1002", "user": "@crypto_skeptic", "text": "Still not convinced about on-chain AI agents. Seems like vaporware to me. Show me a real use case.", "likes": 22, "retweets": 5},
{"id": "1003", "user": "@sol_dev_anna", "text": "Just deployed my first Anchor program. The Solana dev experience is really improving!", "likes": 156, "retweets": 43},
{"id": "1004", "user": "@nft_maxi", "text": "Floor prices on Tensor are mooning. Madlads up 30% this week.", "likes": 891, "retweets": 220},
{"id": "1005", "user": "@ai_researcher", "text": "Has anyone tried AgentX Protocol? Curious about the swarm coordination mechanism.", "likes": 67, "retweets": 12},
{"id": "1006", "user": "@rekt_trader", "text": "Lost 80% on a memecoin rug. This space is a scam. Never trading again.", "likes": 11, "retweets": 2},
{"id": "1007", "user": "@web3_builder", "text": "Building an autonomous agent that auto-manages a DeFi portfolio on Solana. Using AgentX SDK. Love the abstractions.", "likes": 203, "retweets": 67},
{"id": "1008", "user": "@solana_news", "text": "Breaking: Solana validator client diversity reaches 40% with Firedancer going live on mainnet.", "likes": 1240, "retweets": 520},
{"id": "1009", "user": "@anon_whale", "text": "Big SOL buy incoming. Watching the charts closely. RT if you're accumulating.", "likes": 445, "retweets": 180},
{"id": "1010", "user": "@tech_journalist","text": "Interesting thread on how AI agents will reshape DeFi. The combination of LLMs + on-chain execution is genuinely novel.", "likes": 88, "retweets": 34},
]
# ---------------------------------------------------------------------------
# Agent tools
# ---------------------------------------------------------------------------
@dataclass
class Tweet:
id: str
user: str
text: str
likes: int
retweets: int
def fetch_tweet_batch(count: int = 5) -> str:
"""
Fetch a batch of recent tweets from the mock stream.
Returns JSON list of tweet objects.
"""
batch = random.sample(MOCK_TWEETS, min(count, len(MOCK_TWEETS)))
return json.dumps(batch, indent=2)
def classify_tweet(tweet_id: str, tweet_text: str) -> str:
"""
Classify a tweet by topic and sentiment.
Returns: topic (agentx|solana|defi|nft|other), sentiment (positive|negative|neutral),
and whether we should reply (boolean).
"""
text_lower = tweet_text.lower()
# Simple rule-based classification (replace with LLM in production)
if "agentx" in text_lower or "autonomous agent" in text_lower:
topic = "agentx"
should_reply = True
elif "solana" in text_lower or "sol " in text_lower or "anchor" in text_lower:
topic = "solana"
should_reply = True
elif "defi" in text_lower or "yield" in text_lower or "liquidity" in text_lower:
topic = "defi"
should_reply = len(tweet_text) > 50 # only substantive tweets
elif "nft" in text_lower or "floor" in text_lower:
topic = "nft"
should_reply = False
else:
topic = "other"
should_reply = False
# Sentiment heuristic
negative_words = ["rug", "scam", "lost", "rekt", "vaporware", "convinced"]
positive_words = ["flying", "bullish", "mooning", "love", "great", "novel"]
neg_count = sum(1 for w in negative_words if w in text_lower)
pos_count = sum(1 for w in positive_words if w in text_lower)
sentiment = "positive" if pos_count > neg_count else ("negative" if neg_count > pos_count else "neutral")
return json.dumps({
"tweet_id": tweet_id,
"topic": topic,
"sentiment": sentiment,
"should_reply": should_reply,
"reason": f"Topic={topic}, Sentiment={sentiment}",
})
def draft_reply(tweet_id: str, tweet_text: str, tweet_user: str) -> str:
"""
Draft an on-brand reply for a given tweet.
The reply should be helpful, concise, and subtly promote AgentX where relevant.
Max 280 characters. Returns the draft text.
"""
# Templates for different scenarios (LLM generates these in production)
templates = {
"agentx": [
f"Great question @{tweet_user.lstrip('@')}! AgentX agents use a ReAct loop with Solana-native execution. Check out our docs at docs.agentx.io for the swarm coordination deep-dive! 🤖",
f"Glad you're exploring AgentX! The swarm coordination uses a P2P message bus — agents negotiate tasks without a central coordinator. Open source: github.com/agentx-protocol 🔗",
],
"solana": [
f"Solana's throughput makes it perfect for high-frequency agent operations. We're building exactly this at AgentX Protocol — autonomous agents with on-chain execution! ⚡",
f"The Solana dev experience keeps getting better! If you're building autonomous AI agents on it, check out AgentX-Core — handles the Solana integration for you 🛠️",
],
"defi": [
f"On-chain AI agents are the next evolution of DeFi automation. AgentX agents can manage positions, rebalance, and execute strategies 24/7. No bots, actual agents 🤖",
],
}
topic = "agentx" if "agentx" in tweet_text.lower() else ("solana" if "solana" in tweet_text.lower() else "defi")
replies = templates.get(topic, ["Interesting perspective! The future of autonomous on-chain agents is being built now. 🚀"])
return random.choice(replies)
def post_reply(tweet_id: str, reply_text: str, dry_run: bool = True) -> str:
"""
Post a reply to a tweet.
In dry_run mode (default), just logs the action without posting.
"""
if dry_run:
return json.dumps({
"status": "DRY_RUN",
"tweet_id": tweet_id,
"reply": reply_text,
"timestamp": datetime.utcnow().isoformat(),
"message": "Set DRY_RUN=false to post for real",
})
else:
# Production: use tweepy client here
return json.dumps({
"status": "ERROR",
"message": "Live posting requires TWITTER_BEARER_TOKEN in .env",
})
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
def build_social_agent(dry_run: bool = True) -> Agent:
dry_run_flag = dry_run
def post_reply_wrapped(tweet_id: str, reply_text: str) -> str:
return post_reply(tweet_id, reply_text, dry_run=dry_run_flag)
tools = [
Tool(fetch_tweet_batch, name="fetch_tweets", description="Fetch a batch of recent tweets"),
Tool(classify_tweet, name="classify_tweet", description="Classify a tweet by topic and sentiment"),
Tool(draft_reply, name="draft_reply", description="Draft an on-brand reply for a tweet"),
Tool(post_reply_wrapped, name="post_reply", description="Post a reply (dry_run safe)"),
]
system_prompt = """You are AgentX SocialBot, an autonomous social media agent for the AgentX Protocol.
Your mission:
1. Fetch a batch of tweets
2. Classify each tweet — only engage with relevant ones (agentx, solana, defi topics)
3. For relevant tweets: draft an appropriate reply, then post it
4. Skip negative/toxic content and off-topic tweets
5. Never reply to the same tweet twice
6. Be genuinely helpful and avoid spammy marketing language
After processing all tweets, provide a FINAL ANSWER: with a summary of actions taken."""
return Agent(
name="social-bot-v1",
model=os.getenv("AGENTX_MODEL", "gpt-4o"),
tools=tools,
system_prompt=system_prompt,
max_iterations=20,
verbose=True,
)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="AgentX Social Agent")
parser.add_argument("--count", type=int, default=5, help="Number of tweets to process")
parser.add_argument("--live", action="store_true", help="Disable dry-run (post for real)")
args = parser.parse_args()
dry_run = not args.live
mode = "[yellow]DRY RUN[/yellow]" if dry_run else "[bold red]LIVE MODE[/bold red]"
console.print(f"\n[bold cyan]AgentX Social Agent[/bold cyan] — Mode: {mode}\n")
agent = build_social_agent(dry_run=dry_run)
task = (
f"Process the next {args.count} tweets from the stream. "
"For each tweet: classify it, and if relevant, draft and post a reply. "
"Skip irrelevant or negative tweets. Summarize what you did."
)
result = agent.run(task)
console.print("\n[bold green]=== SUMMARY ===[/bold green]")
console.print(result.output)
console.print(f"\nIterations: {result.iterations} | Tool calls: {len(result.tool_calls)}")