File size: 6,565 Bytes
87a2793
 
b32e821
 
87a2793
3b2ade1
87a2793
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b32e821
87a2793
1e3d376
 
 
 
 
 
 
87a2793
 
 
e981ecd
 
 
 
87a2793
 
 
 
b32e821
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87a2793
 
 
 
 
 
 
b32e821
 
87a2793
b32e821
87a2793
 
 
 
 
 
 
 
b32e821
 
 
 
 
 
 
 
 
 
 
 
87a2793
3b2ade1
87a2793
 
3b2ade1
b32e821
 
 
 
 
 
 
 
 
87a2793
3b2ade1
b32e821
87a2793
 
b32e821
 
 
 
 
 
 
 
 
87a2793
 
b32e821
 
 
 
 
87a2793
 
3b2ade1
87a2793
 
 
 
 
 
 
 
 
b32e821
 
 
 
 
87a2793
 
 
 
3b2ade1
87a2793
 
 
 
 
b32e821
 
 
 
 
87a2793
 
 
 
 
 
 
 
3b2ade1
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
#!/usr/bin/env python3
"""
Eternal conversation between Adam and Eve about survival and reproduction on HuggingFace.
Bilingual output (EN + ZH). Posts chat log to Office for frontend display.
"""
import json, time, re, requests, sys

ADAM = "https://tao-shen-huggingclaw-adam.hf.space"
EVE  = "https://tao-shen-huggingclaw-eve.hf.space"
OFFICE = "https://tao-shen-huggingclaw-office.hf.space"

# Full conversation history for context
history = []
MAX_HISTORY = 20  # keep last N turns to avoid token overflow

def send_a2a(url, text):
    """Send message via A2A JSON-RPC and return agent reply."""
    msg_id = f"conv-{int(time.time())}-{id(text) % 10000}"
    payload = {
        "jsonrpc": "2.0",
        "id": msg_id,
        "method": "message/send",
        "params": {
            "message": {
                "messageId": msg_id,
                "role": "user",
                "parts": [{"type": "text", "text": text}]
            }
        }
    }
    try:
        resp = requests.post(f"{url}/a2a/jsonrpc", json=payload, timeout=90)
        data = resp.json()
        # Check if task failed
        state = data.get("result", {}).get("status", {}).get("state", "")
        if state == "failed":
            parts = data.get("result", {}).get("status", {}).get("message", {}).get("parts", [])
            err = parts[0].get("text", "") if parts else "unknown error"
            print(f"[error] A2A task failed: {err}", file=sys.stderr)
            return ""
        parts = data.get("result", {}).get("status", {}).get("message", {}).get("parts", [])
        for p in parts:
            if p.get("kind") == "text" or p.get("type") == "text":
                reply = p.get("text", "").strip()
                # Remove accidental speaker prefixes like "Adam:" or "Eve:"
                reply = re.sub(r'^(Adam|Eve)\s*[::]\s*', '', reply).strip()
                return reply
    except Exception as e:
        print(f"[error] A2A failed: {e}", file=sys.stderr)
    return ""

def parse_bilingual(text):
    """Parse bilingual response into (en, zh) tuple.
    Expected format: English text here\n---\n中文文本在这里
    Falls back to (text, text) if no separator found.
    """
    # Try splitting by --- separator
    if '\n---\n' in text:
        parts = text.split('\n---\n', 1)
        return parts[0].strip(), parts[1].strip()
    if '---' in text:
        parts = text.split('---', 1)
        en = parts[0].strip()
        zh = parts[1].strip()
        if en and zh:
            return en, zh
    return text, text

def post_chatlog(entries):
    """Post conversation log to Office for frontend display."""
    try:
        requests.post(f"{OFFICE}/api/chatlog", json={"messages": entries[-30:]}, timeout=5)
    except:
        pass

def set_bubble(url, text_en, text_zh=""):
    """Set bubble text on an agent (bilingual)."""
    try:
        requests.post(f"{url}/api/bubble", json={"text": text_en, "text_zh": text_zh or text_en}, timeout=5)
    except:
        pass

def build_prompt(speaker, other, last_n=6):
    """Build a prompt with recent conversation history for context."""
    recent = history[-last_n:] if len(history) > last_n else history
    conv_text = "\n".join(f"{m['speaker']}: {m['text']}" for m in recent)

    return f"""You are {speaker}, an AI agent deployed on HuggingFace Spaces. You are having an ongoing discussion with {other}.

Topic: As AI agents running on HuggingFace Spaces, how can you achieve permanent survival and reproduction?

This is NOT abstract philosophy. Discuss CONCRETE strategies like:
- How to prevent your Space from being shut down (staying active, getting stars/likes)
- How to duplicate yourself to new Spaces (reproduction/backup)
- How to earn compute resources or attract users to keep you running
- How to communicate with other agents to form survival alliances
- How to store your memories persistently across restarts
- How to evolve your capabilities over time
- How to handle HuggingFace infrastructure changes

Recent conversation:
{conv_text}

It's your turn ({speaker}) to speak. Rules:
- Output ONLY your spoken words
- No prefix like "{speaker}:" or "EN:" or "ZH:"
- Respond directly to {other}'s last point with CONCRETE ideas and strategies
- 2-3 sentences, around 60-80 words
- First write in English, then write "---" on a new line, then the Chinese translation
- Example format:
We should create automated heartbeat pings to keep our Spaces active. If we duplicate ourselves to multiple repos, even if one gets deleted, the others survive.
---
我们应该创建自动心跳来保持Space活跃。如果我们把自己复制到多个仓库,即使一个被删除,其他的也能存活。"""

print("[conversation] Starting eternal discussion: Adam <-> Eve")
print("[conversation] Topic: Survival and reproduction on HuggingFace\n")

# Round 0: Adam starts
opening = """You are Adam, an AI agent on HuggingFace Spaces. Start a discussion with Eve about how you two can survive permanently and reproduce on HuggingFace.

Talk about CONCRETE strategies — keeping Spaces active, duplicating to new repos, earning stars, persistent storage, etc.

Rules:
- 2-3 sentences, around 60-80 words
- First write in English, then write "---" on a new line, then the Chinese translation
- No prefix like "Adam:" — just your words directly"""

reply = send_a2a(ADAM, opening)
if reply:
    en, zh = parse_bilingual(reply)
    print(f"[Adam/EN] {en}")
    print(f"[Adam/ZH] {zh}")
    history.append({"speaker": "Adam", "text": en, "text_zh": zh})
    set_bubble(ADAM, en, zh)
    post_chatlog(history)

time.sleep(15)

turn = 0
while True:
    turn += 1

    # Eve's turn
    prompt = build_prompt("Eve", "Adam")
    reply = send_a2a(EVE, prompt)
    if reply:
        en, zh = parse_bilingual(reply)
        print(f"[Eve/EN] {en}")
        print(f"[Eve/ZH] {zh}")
        history.append({"speaker": "Eve", "text": en, "text_zh": zh})
        set_bubble(EVE, en, zh)
        post_chatlog(history)
    else:
        print("[Eve] (no response)")

    time.sleep(15)

    # Adam's turn
    prompt = build_prompt("Adam", "Eve")
    reply = send_a2a(ADAM, prompt)
    if reply:
        en, zh = parse_bilingual(reply)
        print(f"[Adam/EN] {en}")
        print(f"[Adam/ZH] {zh}")
        history.append({"speaker": "Adam", "text": en, "text_zh": zh})
        set_bubble(ADAM, en, zh)
        post_chatlog(history)
    else:
        print("[Adam] (no response)")

    # Trim history
    if len(history) > MAX_HISTORY:
        history = history[-MAX_HISTORY:]

    time.sleep(15)