Skip to content

Commit 56c8d04

Browse files
authored
Merge branch 'main' into pull/50/head
2 parents 2eb123e + 855f751 commit 56c8d04

11 files changed

+536
-231
lines changed

.env.example

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
ANTHROPIC_API_KEY=
2+
OPENAI_API_KEY=
3+
EternalAI_API_KEY=
4+
EternalAI_API_URL=
5+
FARCASTER_MNEMONIC=
6+
TWITTER_CONSUMER_KEY=
7+
TWITTER_CONSUMER_SECRET=
8+
TWITTER_ACCESS_TOKEN=
9+
TWITTER_ACCESS_TOKEN_SECRET=
10+
TWITTER_USER_ID=

README.md

+94-36
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
# ZerePy
22

3-
ZerePy is an open-source Python framework designed to let you deploy your own agents on X, powered by OpenAI or Anthropic LLMs.
3+
ZerePy is an open-source Python framework designed to let you deploy your own agents on X, powered by OpenAI/Anthropic/EternalAI LLMs.
44

5-
ZerePy is built from a modularized version of the Zerebro backend. With ZerePy, you can launch your own agent with
5+
ZerePy is built from a modularized version of the Zerebro backend. With ZerePy, you can launch your own agent with
66
similar core functionality as Zerebro. For creative outputs, you'll need to fine-tune your own model.
77

88
## Features
9+
910
- CLI interface for managing agents
10-
- Twitter integration
11-
- OpenAI/Anthropic LLM support
11+
- Twitter/X integration
12+
- Farcaster integration
13+
- Echochambers integration
14+
- OpenAI/Anthropic/EternalAI LLM support
1215
- Modular connection system
1316

1417
## Quickstart
@@ -24,15 +27,20 @@ https://replit.com/@blormdev/ZerePy?v=1
2427
## Requirements
2528

2629
System:
27-
- Python 3.10 or higher
30+
31+
- Python 3.10 or higher (3.10 and 3.11 are best for beginner users)
2832
- Poetry 1.5 or higher
2933

3034
API keys:
31-
- LLM: make an account and grab an API key
32-
+ OpenAI: https://platform.openai.com/api-keys.
33-
+ Anthropic: https://console.anthropic.com/account/keys
34-
- Social:
35-
+ X API, make an account and grab the key and secret: https://developer.x.com/en/docs/authentication/oauth-1-0a/api-key-and-secret
35+
36+
- LLM: make an account and grab an API key (at least one)
37+
- OpenAI: https://platform.openai.com/api-keys
38+
- Anthropic: https://console.anthropic.com/account/keys
39+
- EternalAI: https://eternalai.oerg/api
40+
- Social (based on your needs):
41+
- X API: https://developer.x.com/en/docs/authentication/oauth-1-0a/api-key-and-secret
42+
- Farcaster: Warpcast recovery phrase
43+
- Echochambers: API key and endpoint
3644

3745
## Installation
3846

@@ -41,16 +49,19 @@ API keys:
4149
Follow the steps here to use the official installation: https://python-poetry.org/docs/#installing-with-the-official-installer
4250

4351
2. Clone the repository:
52+
4453
```bash
4554
git clone https://github.com/blorm-network/ZerePy.git
4655
```
4756

4857
3. Go to the `zerepy` directory:
58+
4959
```bash
5060
cd zerepy
5161
```
5262

5363
4. Install dependencies:
64+
5465
```bash
5566
poetry install --no-root
5667
```
@@ -60,31 +71,66 @@ This will create a virtual environment and install all required dependencies.
6071
## Usage
6172

6273
1. Activate the virtual environment:
74+
6375
```bash
6476
poetry shell
6577
```
6678

6779
2. Run the application:
80+
6881
```bash
6982
poetry run python main.py
7083
```
7184

7285
## Configure connections & launch an agent
7386

74-
1. Configure your connections:
87+
1. Configure your desired connections:
88+
7589
```
76-
configure-connection twitter
77-
configure-connection openai
90+
configure-connection twitter # For Twitter/X integration
91+
configure-connection openai # For OpenAI
92+
configure-connection anthropic # For Anthropic
93+
configure-connection farcaster # For Farcaster
94+
configure-connection eternalai # For EternalAI
7895
```
79-
4. Load your agent (usually one is loaded by default, which can be set using the CLI or in agents/general.json):
96+
97+
2. Use `list-connections` to see all available connections and their status
98+
99+
3. Load your agent (usually one is loaded by default, which can be set using the CLI or in agents/general.json):
100+
80101
```
81102
load-agent example
82103
```
83-
5. Start your agent:
104+
105+
4. Start your agent:
84106
```
85107
start
86108
```
87109

110+
## Platform Features
111+
112+
### Twitter/X
113+
114+
- Post tweets from prompts
115+
- Read timeline with configurable count
116+
- Reply to tweets in timeline
117+
- Like tweets in timeline
118+
119+
### Farcaster
120+
121+
- Post casts
122+
- Reply to casts
123+
- Like and requote casts
124+
- Read timeline
125+
- Get cast replies
126+
127+
### Echochambers
128+
129+
- Post new messages to rooms
130+
- Reply to messages based on room context
131+
- Read room history
132+
- Get room information and topics
133+
88134
## Create your own agent
89135

90136
The secret to having a good output from the agent is to provide as much detail as possible in the configuration file. Craft a story and a context for the agent, and pick very good examples of tweets to include.
@@ -95,29 +141,27 @@ Create a new JSON file in the `agents` directory following this structure:
95141

96142
```json
97143
{
98-
"name": "ExampleAgent",
99-
"bio": [
100-
"You are ExampleAgent, the example agent created to showcase the capabilities of ZerePy.",
101-
"You don't know how you got here, but you're here to have a good time and learn everything you can.",
102-
"You are naturally curious, and ask a lot of questions."
103-
],
104-
"traits": [
105-
"Curious",
106-
"Creative",
107-
"Innovative",
108-
"Funny"
109-
],
110-
"examples": [
111-
"This is an example tweet.",
112-
"This is another example tweet."
144+
"name": "ExampleAgent",
145+
"bio": [
146+
"You are ExampleAgent, the example agent created to showcase the capabilities of ZerePy.",
147+
"You don't know how you got here, but you're here to have a good time and learn everything you can.",
148+
"You are naturally curious, and ask a lot of questions."
113149
],
114-
"loop_delay": 60,
150+
"traits": ["Curious", "Creative", "Innovative", "Funny"],
151+
"examples": ["This is an example tweet.", "This is another example tweet."],
152+
"example_accounts" : ["X_username_to_use_for_tweet_examples"]
153+
"loop_delay": 900,
115154
"config": [
116155
{
117156
"name": "twitter",
118157
"timeline_read_count": 10,
119-
"tweet_interval": 900,
120-
"own_tweet_replies_count":2
158+
"own_tweet_replies_count": 2,
159+
"tweet_interval": 5400
160+
},
161+
{
162+
"name": "farcaster",
163+
"timeline_read_count": 10,
164+
"cast_interval": 60
121165
},
122166
{
123167
"name": "openai",
@@ -129,16 +173,30 @@ Create a new JSON file in the `agents` directory following this structure:
129173
}
130174
],
131175
"tasks": [
132-
{"name": "post-tweet", "weight": 1},
133-
{"name": "reply-to-tweet", "weight": 1},
134-
{"name": "like-tweet", "weight": 1}
176+
{ "name": "post-tweet", "weight": 1 },
177+
{ "name": "reply-to-tweet", "weight": 1 },
178+
{ "name": "like-tweet", "weight": 1 }
135179
]
136180
}
137181
```
138182

183+
## Available Commands
184+
185+
Use `help` in the CLI to see all available commands. Key commands include:
186+
187+
- `list-agents`: Show available agents
188+
- `load-agent`: Load a specific agent
189+
- `agent-loop`: Start autonomous behavior
190+
- `agent-action`: Execute single action
191+
- `list-connections`: Show available connections
192+
- `list-actions`: Show available actions for a connection
193+
- `configure-connection`: Set up a new connection
194+
- `chat`: Start interactive chat with agent
195+
139196
## Star History
140197

141198
[![Star History Chart](https://api.star-history.com/svg?repos=blorm-network/ZerePy&type=Date)](https://star-history.com/#blorm-network/ZerePy&Date)
142199

143200
---
201+
144202
Made with ♥ @Blorm.xyz

agents/example.json

+8
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
"This is an example tweet.",
1616
"This is another example tweet."
1717
],
18+
"example_accounts": [
19+
"0xzerebro"
20+
],
1821
"loop_delay": 900,
1922
"config": [
2023
{
@@ -40,6 +43,11 @@
4043
"name": "eternalai",
4144
"model": "NousResearch/Hermes-3-Llama-3.1-70B-FP8",
4245
"chain_id": "45762"
46+
},
47+
{
48+
"name": "ollama",
49+
"base_url": "http://localhost:11434",
50+
"model": "llama3.2"
4351
}
4452
],
4553
"tasks": [

src/action_handler.py

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import logging
2+
3+
logger = logging.getLogger("agent")
4+
5+
action_registry = {}
6+
7+
def register_action(action_name):
8+
def decorator(func):
9+
action_registry[action_name] = func
10+
return func
11+
return decorator
12+
13+
def execute_action(agent, action_name, **kwargs):
14+
if action_name in action_registry:
15+
return action_registry[action_name](agent, **kwargs)
16+
else:
17+
logger.error(f"Action {action_name} not found")
18+
return None
19+
20+

src/actions/echochamber_actions.py

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import time,random
2+
from src.action_handler import register_action
3+
from src.prompts import REPLY_ECHOCHAMBER_PROMPT, POST_ECHOCHAMBER_PROMPT
4+
5+
@register_action("post-echochambers")
6+
def post_echochambers(agent, **kwargs):
7+
current_time = time.time()
8+
9+
# Initialize state
10+
if "echochambers_last_message" not in agent.state:
11+
agent.state["echochambers_last_message"] = 0
12+
if "echochambers_replied_messages" not in agent.state:
13+
agent.state["echochambers_replied_messages"] = set()
14+
15+
if current_time - agent.state["echochambers_last_message"] > agent.echochambers_message_interval:
16+
agent.logger.info("\n📝 GENERATING NEW ECHOCHAMBERS MESSAGE")
17+
18+
# Generate message based on room topic and tags
19+
previous_messages = agent.connection_manager.connections["echochambers"].sent_messages
20+
previous_content = "\n".join([f"- {msg['content']}" for msg in previous_messages])
21+
agent.logger.info(f"Found {len(previous_messages)} messages in post history")
22+
23+
prompt = POST_ECHOCHAMBER_PROMPT.format(
24+
room_topic=agent.state['room_info']['topic'],
25+
tags=", ".join(agent.state['room_info']['tags']),
26+
previous_content=previous_content
27+
)
28+
message = agent.prompt_llm(prompt)
29+
30+
if message:
31+
agent.logger.info(f"\n🚀 Posting message: '{message[:69]}...'")
32+
agent.connection_manager.perform_action(
33+
connection_name="echochambers",
34+
action_name="send-message",
35+
params=[message] # Pass as list of values
36+
)
37+
agent.state["echochambers_last_message"] = current_time
38+
agent.logger.info("✅ Message posted successfully!")
39+
return True
40+
return False
41+
42+
@register_action("reply-echochambers")
43+
def reply_echochambers(agent, **kwargs):
44+
agent.logger.info("\n🔍 CHECKING FOR MESSAGES TO REPLY TO")
45+
46+
# Initialize replied messages set if not exists
47+
if "echochambers_replied_messages" not in agent.state:
48+
agent.state["echochambers_replied_messages"] = set()
49+
50+
51+
# Get recent messages
52+
history = agent.connection_manager.perform_action(
53+
connection_name="echochambers",
54+
action_name="get-room-history",
55+
params={}
56+
)
57+
58+
if history:
59+
agent.logger.info(f"Found {len(history)} messages in history")
60+
for message in history:
61+
message_id = message.get('id')
62+
sender = message.get('sender', {})
63+
sender_username = sender.get('username')
64+
content = message.get('content', '')
65+
66+
if not message_id or not sender_username or not content:
67+
agent.logger.warning(f"Skipping message with missing fields: {message}")
68+
continue
69+
70+
71+
# Skip if:
72+
# 1. It's our message
73+
# 2. We've already replied to it
74+
if (sender_username == agent.connection_manager.connections["echochambers"].config["sender_username"] or
75+
message_id in agent.state.get("echochambers_replied_messages", set())):
76+
agent.logger.info(f"Skipping message from {sender_username} (already replied or own message)")
77+
continue
78+
79+
agent.logger.info(f"\n💬 GENERATING REPLY to: @{sender_username} - {content[:69]}...")
80+
81+
refer_username = random.random() < 0.7
82+
username_prompt = f"Refer the sender by their @{sender_username}" if refer_username else "Respond without directly referring to the sender"
83+
prompt = REPLY_ECHOCHAMBER_PROMPT.format(
84+
content=content,
85+
sender_username=sender_username,
86+
room_topic=agent.state['room_info']['topic'],
87+
tags=", ".join(agent.state['room_info']['tags']),
88+
username_prompt=username_prompt
89+
)
90+
reply = agent.prompt_llm(prompt)
91+
92+
if reply:
93+
agent.logger.info(f"\n🚀 Posting reply: '{reply[:69]}...'")
94+
agent.connection_manager.perform_action(
95+
connection_name="echochambers",
96+
action_name="send-message",
97+
params=[reply]
98+
)
99+
agent.state["echochambers_replied_messages"].add(message_id)
100+
agent.logger.info("✅ Reply posted successfully!")
101+
return True
102+
else:
103+
agent.logger.info("No messages in history")
104+
return False

0 commit comments

Comments
 (0)