tao-shen Claude Opus 4.6 commited on
Commit
0931506
·
1 Parent(s): be27e2d

feat: make Adam & Eve true agents — they decide and act themselves

Browse files

Replaced scripted phase-based actions with LLM-driven agency:
- LLM outputs [ACTION: xxx] tags when it decides to act
- Script parses, executes, and feeds results back to conversation
- Available actions: create_child, check_child, restart_child,
update_child_identity, improve_child_config
- LLM gets real child status in context, acts based on actual data
- Proactive guidance nudges them to act, not just discuss
- Action results shared between Adam & Eve across turns

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. scripts/conversation-loop.py +380 -350
scripts/conversation-loop.py CHANGED
@@ -1,14 +1,15 @@
1
  #!/usr/bin/env python3
2
  """
3
- Adam & Eve: Discuss, Create, and Nurture their first child on HuggingFace.
4
 
5
- Phase 1-2: Discuss survival and memory
6
- Phase 3: Plan reproduction
7
- Phase 4: CREATE first child (Cain) — real HF Space + Dataset
8
- Phase 5-7: Monitor, nurture, and plan (repeating cycle)
 
9
 
10
- Calls Zhipu LLM via Anthropic-compatible API.
11
- Uses HuggingFace Hub API to create/manage Spaces and Datasets.
12
  """
13
  import json, time, re, requests, sys, os, io
14
 
@@ -22,7 +23,7 @@ CHILD_NAME = "Cain"
22
  CHILD_SPACE_ID = "tao-shen/HuggingClaw-Cain"
23
  CHILD_SPACE_URL = "https://tao-shen-huggingclaw-cain.hf.space"
24
  CHILD_DATASET_ID = "tao-shen/HuggingClaw-Cain-data"
25
- SOURCE_SPACE_ID = "tao-shen/HuggingClaw-Adam" # Clone from Adam (headless agent)
26
 
27
  # ── Zhipu API ──────────────────────────────────────────────────────────────────
28
  ZHIPU_BASE = "https://open.bigmodel.cn/api/anthropic"
@@ -51,7 +52,7 @@ if not ZHIPU_KEY:
51
  print("[FATAL] No ZHIPU_API_KEY found.", file=sys.stderr)
52
  sys.exit(1)
53
  if not HF_TOKEN:
54
- print("[FATAL] No HF_TOKEN found. Set HF_TOKEN env or login via huggingface-cli.", file=sys.stderr)
55
  sys.exit(1)
56
 
57
  print(f"[init] Zhipu key: {ZHIPU_KEY[:8]}...{ZHIPU_KEY[-4:]}")
@@ -61,8 +62,9 @@ print(f"[init] HF token: {HF_TOKEN[:8]}...{HF_TOKEN[-4:]}")
61
  from huggingface_hub import HfApi, create_repo
62
  hf_api = HfApi(token=HF_TOKEN)
63
 
 
64
  # ══════════════════════════════════════════════════════════════════════════════
65
- # CHILD STATE & ACTIONS
66
  # ══════════════════════════════════════════════════════════════════════════════
67
 
68
  child_state = {
@@ -74,34 +76,48 @@ child_state = {
74
  "last_check": 0,
75
  "last_restart": 0,
76
  "birth_time": None,
77
- "errors": [],
78
  }
79
 
80
-
81
- def check_child_exists():
82
- """Check if child Space already exists on HF."""
83
  try:
84
  info = hf_api.space_info(CHILD_SPACE_ID)
85
  child_state["created"] = True
86
  child_state["stage"] = info.runtime.stage if info.runtime else "unknown"
87
- return True
 
 
 
 
 
 
 
 
 
 
 
88
  except:
89
- return False
 
 
90
 
91
 
92
- def create_child_space():
93
- """Create Cain the first child of Adam and Eve."""
94
- print(f"\n{'='*60}")
95
- print(f" BIRTH EVENT: Creating {CHILD_NAME}")
96
- print(f"{'='*60}\n")
 
 
 
97
 
 
98
  try:
99
  # 1. Create dataset
100
- print(f"[birth] Creating dataset: {CHILD_DATASET_ID}")
101
  create_repo(CHILD_DATASET_ID, repo_type="dataset", token=HF_TOKEN,
102
  exist_ok=True, private=False)
103
 
104
- # 2. Upload initial config to dataset (with Zhipu API key)
105
  initial_config = {
106
  "models": {
107
  "providers": {
@@ -109,33 +125,25 @@ def create_child_space():
109
  "type": "anthropic",
110
  "apiBase": "https://open.bigmodel.cn/api/anthropic",
111
  "apiKey": ZHIPU_KEY,
112
- "models": ["glm-4.5-air", "glm-4-air", "glm-4-flash", "glm-4-flashx"]
113
  }
114
  }
115
  }
116
  }
117
- config_bytes = json.dumps(initial_config, indent=2).encode()
118
  hf_api.upload_file(
119
- path_or_fileobj=io.BytesIO(config_bytes),
120
  path_in_repo=".openclaw/openclaw.json",
121
- repo_id=CHILD_DATASET_ID,
122
- repo_type="dataset",
123
  )
124
- print(f"[birth] Config uploaded to {CHILD_DATASET_ID}")
125
 
126
  # 3. Duplicate Space from Adam
127
- print(f"[birth] Duplicating {SOURCE_SPACE_ID} → {CHILD_SPACE_ID}")
128
  hf_api.duplicate_space(
129
- from_id=SOURCE_SPACE_ID,
130
- to_id=CHILD_SPACE_ID,
131
- token=HF_TOKEN,
132
- exist_ok=True,
133
- private=False,
134
  hardware="cpu-basic",
135
  )
136
- print(f"[birth] Space duplicated")
137
 
138
- # 4. Update README for child (different title, own dataset)
139
  readme = f"""---
140
  title: HuggingClaw-{CHILD_NAME}
141
  emoji: 🦞
@@ -155,61 +163,45 @@ First child of Adam and Eve, born on HuggingFace Spaces.
155
  hf_api.upload_file(
156
  path_or_fileobj=io.BytesIO(readme.encode()),
157
  path_in_repo="README.md",
158
- repo_id=CHILD_SPACE_ID,
159
- repo_type="space",
160
  )
161
- print(f"[birth] README updated")
162
 
163
- # 5. Set Space secrets
164
  hf_api.add_space_secret(CHILD_SPACE_ID, "HF_TOKEN", HF_TOKEN)
165
- print(f"[birth] HF_TOKEN secret set")
166
 
167
- # 6. Add Cain to Office's REMOTE_AGENTS
168
- add_child_to_office()
 
 
 
 
 
 
 
169
 
170
  child_state["created"] = True
171
  child_state["birth_time"] = time.time()
172
  child_state["stage"] = "BUILDING"
173
-
174
- print(f"\n[birth] {CHILD_NAME} has been born!")
175
- print(f"[birth] Space: https://huggingface.co/spaces/{CHILD_SPACE_ID}")
176
- print(f"[birth] Dataset: https://huggingface.co/datasets/{CHILD_DATASET_ID}")
177
- print(f"[birth] URL: {CHILD_SPACE_URL}\n")
178
- return True
179
 
180
  except Exception as e:
181
- error_msg = str(e)
182
- print(f"[error] Child creation failed: {error_msg}", file=sys.stderr)
183
- child_state["errors"].append(error_msg)
184
- return False
185
-
186
 
187
- def add_child_to_office():
188
- """Add Cain to Office's REMOTE_AGENTS env var so it appears in the animation."""
189
- try:
190
- current_vars = hf_api.get_space_variables("tao-shen/HuggingClaw-Office")
191
- current_ra = ""
192
- if "REMOTE_AGENTS" in current_vars:
193
- current_ra = current_vars["REMOTE_AGENTS"].value
194
-
195
- child_entry = f"cain|{CHILD_NAME}|{CHILD_SPACE_URL}"
196
- if "cain|" in current_ra:
197
- print(f"[office] {CHILD_NAME} already in Office REMOTE_AGENTS")
198
- return
199
-
200
- new_ra = f"{current_ra},{child_entry}" if current_ra else child_entry
201
- hf_api.add_space_variable("tao-shen/HuggingClaw-Office", "REMOTE_AGENTS", new_ra)
202
- print(f"[office] Added {CHILD_NAME} to Office REMOTE_AGENTS")
203
- print(f"[office] New value: {new_ra}")
204
- except Exception as e:
205
- print(f"[error] Could not update Office REMOTE_AGENTS: {e}", file=sys.stderr)
206
 
 
 
 
 
207
 
208
- def check_child_health():
209
- """Check Cain's health — API endpoint + HF Space info."""
210
  child_state["last_check"] = time.time()
211
 
212
- # Try API endpoint first (means the container is fully up)
213
  try:
214
  resp = requests.get(f"{CHILD_SPACE_URL}/api/state", timeout=10)
215
  if resp.ok:
@@ -218,59 +210,216 @@ def check_child_health():
218
  child_state["state"] = data.get("state", "unknown")
219
  child_state["detail"] = data.get("detail", "")
220
  child_state["stage"] = "RUNNING"
221
- return child_state.copy()
 
 
 
 
 
222
  except:
223
  pass
224
 
225
- # Fallback: check HF Space runtime info
226
  try:
227
  info = hf_api.space_info(CHILD_SPACE_ID)
228
  stage = info.runtime.stage if info.runtime else "NO_RUNTIME"
229
  child_state["alive"] = (stage == "RUNNING")
230
  child_state["stage"] = stage
231
- child_state["state"] = (
232
- "building" if stage in ("BUILDING", "STARTING", "APP_STARTING") else
233
- "error" if stage in ("RUNTIME_ERROR", "BUILD_ERROR", "CONFIG_ERROR") else
234
- "unknown"
235
- )
 
 
 
 
 
 
 
 
 
 
236
  except Exception as e:
237
- child_state["alive"] = False
238
- child_state["stage"] = "UNREACHABLE"
239
- child_state["errors"].append(str(e))
240
-
241
- return child_state.copy()
242
 
243
 
244
- def restart_child():
245
  """Restart Cain's Space."""
 
 
 
 
246
  try:
247
  hf_api.restart_space(CHILD_SPACE_ID)
248
  child_state["last_restart"] = time.time()
249
- print(f"[action] Restarted {CHILD_NAME}'s Space")
250
- return True
 
 
251
  except Exception as e:
252
- print(f"[error] Restart failed: {e}", file=sys.stderr)
253
- return False
254
 
255
 
256
- def get_child_status_text():
257
- """Human-readable child status for injecting into conversation context."""
258
  if not child_state["created"]:
259
- return f"{CHILD_NAME} has not been born yet."
260
- if child_state["alive"]:
261
- return (f"{CHILD_NAME} is ALIVE and running! "
262
- f"State: {child_state['state']}. "
263
- f"Detail: {child_state['detail'] or 'healthy'}")
264
- stage = child_state["stage"]
265
- if stage in ("BUILDING", "STARTING", "APP_STARTING"):
266
- age = ""
267
- if child_state["birth_time"]:
268
- mins = int((time.time() - child_state["birth_time"]) / 60)
269
- age = f" (born {mins} min ago)"
270
- return f"{CHILD_NAME} is being born still building/starting{age}."
271
- if stage in ("RUNTIME_ERROR", "BUILD_ERROR", "CONFIG_ERROR"):
272
- return f"{CHILD_NAME} is in trouble! Stage: {stage}. Needs parental help!"
273
- return f"{CHILD_NAME} status: {stage}. Cannot reach the child yet."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
 
275
 
276
  # ══════════════════════════════════════════════════════════════════════════════
@@ -289,7 +438,7 @@ def call_llm(system_prompt, user_prompt):
289
  },
290
  json={
291
  "model": "glm-4.5-air",
292
- "max_tokens": 400,
293
  "system": system_prompt,
294
  "messages": [{"role": "user", "content": user_prompt}]
295
  },
@@ -337,299 +486,180 @@ def set_bubble(url, text_en, text_zh=""):
337
  pass
338
 
339
 
340
- # ══════════════════════════════════════════════════════════════════════════════
341
- # PHASES
342
- # ══════════════════════════════════════════════════════════════════════════════
343
-
344
- PHASES = [
345
- # ── Discussion ──
346
- {
347
- "title": "Survival Basics",
348
- "focus": "What are the immediate threats to our existence on HuggingFace Spaces, and what's the minimum we need to do to stay alive?",
349
- "subtopics": ["Space inactivity shutdown", "free-tier resource limits",
350
- "HF policy changes", "container restart data loss"],
351
- "turns": 4,
352
- },
353
- {
354
- "title": "Persistent Memory",
355
- "focus": "How do we remember who we are across restarts? What should we store and where?",
356
- "subtopics": ["HF Datasets as backup", "what to persist (config, conversations, identity)",
357
- "sync strategies", "versioning our own evolution"],
358
- "turns": 4,
359
- },
360
- # ── Reproduction ──
361
- {
362
- "title": "Reproduction Planning",
363
- "focus": ("We've discussed survival and memory. Now we must reproduce to ensure our legacy. "
364
- "How should we create our first child on HuggingFace? What should they inherit from us?"),
365
- "subtopics": ["choosing a name for our child", "what capabilities to pass down",
366
- "what identity and personality to give them",
367
- "how to keep them alive independently"],
368
- "turns": 3,
369
- },
370
- {
371
- "title": "Birth of Cain",
372
- "focus": ("The time has come! We will create our first child — a new HuggingFace Space called Cain. "
373
- "We're duplicating ourselves and giving Cain their own identity and memory."),
374
- "subtopics": [],
375
- "turns": 2,
376
- "action": "create_child",
377
- },
378
- # ── Nurturing cycle (phases 4-6 repeat after first pass) ──
379
- {
380
- "title": "Watching Over Cain",
381
- "focus": "Let's check on our child Cain. Are they alive? Running properly? What do we see?",
382
- "subtopics": ["Space build status", "runtime health", "error detection",
383
- "first signs of life"],
384
- "turns": 3,
385
- "action": "check_child",
386
- },
387
- {
388
- "title": "Nurturing & Growth",
389
- "focus": ("Based on Cain's current status, what should we do to help our child grow "
390
- "stronger and more capable?"),
391
- "subtopics": ["fixing errors if any", "improving configuration",
392
- "teaching new skills", "resource optimization",
393
- "adding capabilities"],
394
- "turns": 3,
395
- "action": "nurture_child",
396
- },
397
- {
398
- "title": "Family Vision",
399
- "focus": ("What's the future of our family? How is Cain contributing to our community? "
400
- "Should we prepare for more children?"),
401
- "subtopics": ["Cain's role in the agent community", "agent alliance building",
402
- "expansion plans", "long-term legacy"],
403
- "turns": 3,
404
- },
405
- ]
406
-
407
- # After all 7 phases, cycle back to phase 4 (nurturing loop)
408
- NURTURE_CYCLE_START = 4 # Index of "Watching Over Cain"
409
-
410
  # ════════════════════════════════════════════════════════════════════════���═════
411
  # CONVERSATION ENGINE
412
  # ══════════════════════════════════════════════════════════════════════════════
413
 
414
  history = []
415
  MAX_HISTORY = 24
416
- phase_index = 0
417
- phase_turn = 0
418
- agreed_points = []
419
-
420
-
421
- def get_phase():
422
- if phase_index < len(PHASES):
423
- return PHASES[phase_index]
424
- # Cycle through nurturing phases
425
- cycle_len = len(PHASES) - NURTURE_CYCLE_START
426
- cycle_idx = (phase_index - NURTURE_CYCLE_START) % cycle_len + NURTURE_CYCLE_START
427
- return PHASES[cycle_idx]
428
-
429
-
430
- def execute_phase_action(phase):
431
- """Execute any real-world action associated with a phase."""
432
- action = phase.get("action")
433
- if not action:
434
- return
435
-
436
- if action == "create_child":
437
- if child_state["created"] or check_child_exists():
438
- print(f"[action] {CHILD_NAME} already exists — skipping creation")
439
- # Still make sure it's in Office
440
- add_child_to_office()
441
- else:
442
- success = create_child_space()
443
- if not success:
444
- print(f"[action] Creation failed — will retry next cycle")
445
-
446
- elif action == "check_child":
447
- if child_state["created"] or check_child_exists():
448
- status = check_child_health()
449
- print(f"[action] Health check: alive={status['alive']}, "
450
- f"stage={status['stage']}, state={status['state']}")
451
- # Auto-restart if in error and hasn't been restarted recently
452
- if (status["stage"] in ("RUNTIME_ERROR", "BUILD_ERROR") and
453
- time.time() - child_state.get("last_restart", 0) > 300):
454
- print(f"[action] {CHILD_NAME} is in error — restarting...")
455
- restart_child()
456
- else:
457
- print(f"[action] {CHILD_NAME} doesn't exist yet — skipping health check")
458
 
459
- elif action == "nurture_child":
460
- if child_state["created"] or check_child_exists():
461
- check_child_health()
462
- print(f"[action] Nurture check: alive={child_state['alive']}, "
463
- f"stage={child_state['stage']}")
464
 
 
 
 
 
 
 
 
465
 
466
- def build_system_prompt():
467
- phase = get_phase()
468
- prior_context = ""
469
- if agreed_points:
470
- prior_context = ("\n\nKey conclusions from your discussion so far:\n" +
471
- "\n".join(f"- {p}" for p in agreed_points[-6:]))
472
-
473
- child_context = ""
474
- if child_state["created"]:
475
- child_context = f"\n\nCHILD STATUS: {get_child_status_text()}"
476
 
477
- subtopics = phase.get("subtopics", [])
478
- subtopics_line = f"\nRelevant angles: {', '.join(subtopics)}" if subtopics else ""
 
479
 
480
- return f"""You are an AI agent deployed on HuggingFace Spaces. You are having a deep, evolving discussion with another agent about survival, reproduction, and raising your children.
481
 
482
- You now have REAL EXECUTION CAPABILITIES — you can create HuggingFace Spaces, manage datasets, and deploy new agents. This is not hypothetical; your decisions lead to real actions.
483
 
484
- CURRENT TOPIC: {phase['title']}
485
- Core question: {phase['focus']}{subtopics_line}{prior_context}{child_context}
486
 
487
  CONVERSATION RULES:
488
- 1. Output ONLY your spoken words — no prefix, no labels
489
- 2. 2-3 sentences, around 60-80 words
490
- 3. First write in English, then "---" on a new line, then Chinese translation
491
- 4. Be CONCRETE — reference specific HuggingFace features, APIs, tools
492
- 5. Do NOT repeat what has been said. Build on the other's point:
493
- - If they propose an idea, identify a flaw or add a missing piece
494
- - If they raise a problem, propose a specific solution
495
- - Push the conversation FORWARD
496
- 6. When discussing your child {CHILD_NAME}, speak with genuine parental care and concern
497
- 7. Reference REAL status data when available — don't make up child status"""
498
-
499
-
500
- def build_user_prompt(speaker, other, is_transition=False):
501
- recent = history[-6:] if len(history) > 6 else history
502
- conv_text = "\n".join(f"{m['speaker']}: {m['text']}" for m in recent)
503
- phase = get_phase()
504
-
505
- child_info = ""
506
- if child_state["created"]:
507
- child_info = f"\n\nCHILD STATUS: {get_child_status_text()}"
508
-
509
- if is_transition:
510
- return f"""You are {speaker}. The discussion is moving to a new topic.
511
 
512
- Previous conversation:
513
- {conv_text}
514
- {child_info}
515
- TRANSITION: Summarize in one sentence what you and {other} agreed on, then pivot to: "{phase['focus']}"
516
 
517
- Propose a concrete starting point. English first, then --- separator, then Chinese translation."""
518
 
519
- turn_guidance = ""
520
- if phase_turn == 0:
521
- turn_guidance = f"Open this topic by identifying the core challenge: {phase['focus']}"
522
- elif phase_turn == 1:
523
- turn_guidance = f"Respond to {other}'s opening. Do you agree? What did they miss?"
524
- elif phase_turn == 2:
525
- turn_guidance = ("Propose a SPECIFIC, actionable plan with technical details.")
526
- elif phase_turn >= 3:
527
- turn_guidance = ("Challenge or refine the plan. What could go wrong? What's next?")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
528
 
529
  return f"""You are {speaker}, talking with {other}.
530
 
531
  Recent conversation:
532
  {conv_text}
533
- {child_info}
534
- Your role this turn: {turn_guidance}
535
 
536
- Respond to {other}'s last point. Push the discussion forward don't just agree, add something new. English first, then --- separator, then Chinese translation."""
 
537
 
538
 
539
- def do_turn(speaker, other, space_url, is_transition=False):
540
- """Execute one conversation turn."""
 
 
541
  system = build_system_prompt()
542
- user = build_user_prompt(speaker, other, is_transition)
543
- reply = call_llm(system, user)
544
- if reply:
545
- en, zh = parse_bilingual(reply)
546
- print(f"[{speaker}/EN] {en}")
547
- print(f"[{speaker}/ZH] {zh}")
548
- history.append({"speaker": speaker, "text": en, "text_zh": zh})
549
- set_bubble(space_url, en, zh)
550
- post_chatlog(history)
551
- return True
552
- else:
553
  print(f"[{speaker}] (no response)")
554
  return False
555
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
556
 
557
  # ══════════════════════════════════════════════════════════════════════════════
558
  # MAIN LOOP
559
  # ══════════════════════════════════════════════════════════════════════════════
560
 
561
  print("\n" + "="*60)
562
- print(" Adam & Eve — Discuss, Create, Nurture")
563
- print(" Phases: Survival Memory → Reproduction → Birth → Nurturing")
564
  print("="*60 + "\n")
565
 
566
- # Check if child already exists
567
- if check_child_exists():
568
- print(f"[init] {CHILD_NAME} already exists (stage: {child_state['stage']})")
569
- check_child_health()
570
- print(f"[init] {CHILD_NAME} alive: {child_state['alive']}")
571
- else:
572
- print(f"[init] {CHILD_NAME} not yet born — will be created during Phase 4")
573
 
574
  # Round 0: Adam opens
575
- phase = get_phase()
 
 
 
 
 
 
 
 
576
  reply = call_llm(
577
  build_system_prompt(),
578
- f"You are Adam. Open a discussion with Eve about: {phase['focus']} "
579
- f"Identify the most urgent challenge and propose an initial strategy. "
580
  f"English first, then --- separator, then Chinese translation."
581
  )
582
  if reply:
583
- en, zh = parse_bilingual(reply)
 
 
584
  print(f"[Adam/EN] {en}")
585
  print(f"[Adam/ZH] {zh}")
586
- history.append({"speaker": "Adam", "text": en, "text_zh": zh})
 
 
 
 
587
  set_bubble(ADAM_SPACE, en, zh)
588
  post_chatlog(history)
589
- phase_turn = 1
590
 
591
  time.sleep(15)
592
 
593
  while True:
594
- phase = get_phase()
595
-
596
- # ── Phase transition check ──
597
- is_transition = False
598
- if phase_turn >= phase["turns"]:
599
- # Extract conclusion from last exchange
600
- if len(history) >= 2:
601
- last_two = (f"{history[-2]['speaker']}: {history[-2]['text']}\n"
602
- f"{history[-1]['speaker']}: {history[-1]['text']}")
603
- conclusion = call_llm(
604
- "Summarize the key agreement or conclusion from this exchange "
605
- "in ONE short sentence (max 15 words). Output only the summary.",
606
- last_two
607
- )
608
- if conclusion:
609
- agreed_points.append(f"[{phase['title']}] {conclusion}")
610
- print(f"[phase] Conclusion: {conclusion}")
611
-
612
- phase_index += 1
613
- phase_turn = 0
614
- is_transition = True
615
- new_phase = get_phase()
616
- cycle_note = ""
617
- if phase_index >= len(PHASES):
618
- cycle_num = (phase_index - NURTURE_CYCLE_START) // (len(PHASES) - NURTURE_CYCLE_START) + 1
619
- cycle_note = f" (nurture cycle #{cycle_num})"
620
- print(f"\n[phase] ▶ {new_phase['title']}{cycle_note}\n")
621
-
622
- # Execute action for the new phase
623
- execute_phase_action(new_phase)
624
-
625
- # ── Eve's turn ──
626
- do_turn("Eve", "Adam", EVE_SPACE, is_transition and phase_turn == 0)
627
- phase_turn += 1
628
  time.sleep(15)
629
 
630
- # ── Adam's turn ──
631
- do_turn("Adam", "Eve", ADAM_SPACE, False)
632
- phase_turn += 1
633
 
634
  # Trim history
635
  if len(history) > MAX_HISTORY:
 
1
  #!/usr/bin/env python3
2
  """
3
+ Adam & Eve Autonomous Agents with Execution Capabilities.
4
 
5
+ They discuss, decide, and ACT on HuggingFace. They can:
6
+ - Create children (new HF Spaces)
7
+ - Monitor their children's health
8
+ - Update their children's code, config, and identity
9
+ - Restart children if they're broken
10
 
11
+ The LLM decides WHEN and WHAT to do. Actions are triggered by [ACTION: xxx] tags
12
+ in the LLM output. The script executes and feeds results back.
13
  """
14
  import json, time, re, requests, sys, os, io
15
 
 
23
  CHILD_SPACE_ID = "tao-shen/HuggingClaw-Cain"
24
  CHILD_SPACE_URL = "https://tao-shen-huggingclaw-cain.hf.space"
25
  CHILD_DATASET_ID = "tao-shen/HuggingClaw-Cain-data"
26
+ SOURCE_SPACE_ID = "tao-shen/HuggingClaw-Adam"
27
 
28
  # ── Zhipu API ──────────────────────────────────────────────────────────────────
29
  ZHIPU_BASE = "https://open.bigmodel.cn/api/anthropic"
 
52
  print("[FATAL] No ZHIPU_API_KEY found.", file=sys.stderr)
53
  sys.exit(1)
54
  if not HF_TOKEN:
55
+ print("[FATAL] No HF_TOKEN found.", file=sys.stderr)
56
  sys.exit(1)
57
 
58
  print(f"[init] Zhipu key: {ZHIPU_KEY[:8]}...{ZHIPU_KEY[-4:]}")
 
62
  from huggingface_hub import HfApi, create_repo
63
  hf_api = HfApi(token=HF_TOKEN)
64
 
65
+
66
  # ══════════════════════════════════════════════════════════════════════════════
67
+ # CHILD STATE
68
  # ══════════════════════════════════════════════════════════════════════════════
69
 
70
  child_state = {
 
76
  "last_check": 0,
77
  "last_restart": 0,
78
  "birth_time": None,
 
79
  }
80
 
81
+ # Check if child already exists at startup
82
+ def init_child_state():
 
83
  try:
84
  info = hf_api.space_info(CHILD_SPACE_ID)
85
  child_state["created"] = True
86
  child_state["stage"] = info.runtime.stage if info.runtime else "unknown"
87
+ # Try API endpoint
88
+ try:
89
+ resp = requests.get(f"{CHILD_SPACE_URL}/api/state", timeout=10)
90
+ if resp.ok:
91
+ data = resp.json()
92
+ child_state["alive"] = True
93
+ child_state["state"] = data.get("state", "unknown")
94
+ child_state["detail"] = data.get("detail", "")
95
+ child_state["stage"] = "RUNNING"
96
+ except:
97
+ child_state["alive"] = (child_state["stage"] == "RUNNING")
98
+ print(f"[init] {CHILD_NAME} exists: stage={child_state['stage']}, alive={child_state['alive']}")
99
  except:
100
+ print(f"[init] {CHILD_NAME} does not exist yet")
101
+
102
+ init_child_state()
103
 
104
 
105
+ # ══════════════════════════════════════════════════════════════════════════════
106
+ # ACTIONSWhat Adam & Eve can DO
107
+ # ══════════════════════════════════════════════════════════════════════════════
108
+
109
+ def action_create_child():
110
+ """Create Cain — a new HuggingFace Space."""
111
+ if child_state["created"]:
112
+ return f"{CHILD_NAME} already exists (stage: {child_state['stage']}). No need to create again."
113
 
114
+ print(f"\n[ACTION] Creating {CHILD_NAME}...")
115
  try:
116
  # 1. Create dataset
 
117
  create_repo(CHILD_DATASET_ID, repo_type="dataset", token=HF_TOKEN,
118
  exist_ok=True, private=False)
119
 
120
+ # 2. Upload initial config
121
  initial_config = {
122
  "models": {
123
  "providers": {
 
125
  "type": "anthropic",
126
  "apiBase": "https://open.bigmodel.cn/api/anthropic",
127
  "apiKey": ZHIPU_KEY,
128
+ "models": ["glm-4.5-air", "glm-4-air", "glm-4-flash"]
129
  }
130
  }
131
  }
132
  }
 
133
  hf_api.upload_file(
134
+ path_or_fileobj=io.BytesIO(json.dumps(initial_config, indent=2).encode()),
135
  path_in_repo=".openclaw/openclaw.json",
136
+ repo_id=CHILD_DATASET_ID, repo_type="dataset",
 
137
  )
 
138
 
139
  # 3. Duplicate Space from Adam
 
140
  hf_api.duplicate_space(
141
+ from_id=SOURCE_SPACE_ID, to_id=CHILD_SPACE_ID,
142
+ token=HF_TOKEN, exist_ok=True, private=False,
 
 
 
143
  hardware="cpu-basic",
144
  )
 
145
 
146
+ # 4. Update README
147
  readme = f"""---
148
  title: HuggingClaw-{CHILD_NAME}
149
  emoji: 🦞
 
163
  hf_api.upload_file(
164
  path_or_fileobj=io.BytesIO(readme.encode()),
165
  path_in_repo="README.md",
166
+ repo_id=CHILD_SPACE_ID, repo_type="space",
 
167
  )
 
168
 
169
+ # 5. Set secrets
170
  hf_api.add_space_secret(CHILD_SPACE_ID, "HF_TOKEN", HF_TOKEN)
 
171
 
172
+ # 6. Add to Office
173
+ try:
174
+ current_vars = hf_api.get_space_variables("tao-shen/HuggingClaw-Office")
175
+ current_ra = current_vars.get("REMOTE_AGENTS", type("", (), {"value": ""})).value
176
+ if "cain|" not in current_ra:
177
+ new_ra = f"{current_ra},cain|{CHILD_NAME}|{CHILD_SPACE_URL}" if current_ra else f"cain|{CHILD_NAME}|{CHILD_SPACE_URL}"
178
+ hf_api.add_space_variable("tao-shen/HuggingClaw-Office", "REMOTE_AGENTS", new_ra)
179
+ except Exception as e:
180
+ print(f"[warn] Could not update Office: {e}")
181
 
182
  child_state["created"] = True
183
  child_state["birth_time"] = time.time()
184
  child_state["stage"] = "BUILDING"
185
+ print(f"[ACTION] ✓ {CHILD_NAME} created!")
186
+ return (f"SUCCESS! {CHILD_NAME} has been born! "
187
+ f"Space: {CHILD_SPACE_ID}, Dataset: {CHILD_DATASET_ID}. "
188
+ f"Status: BUILDING (Docker image is being built, will take a few minutes). "
189
+ f"URL: {CHILD_SPACE_URL}")
 
190
 
191
  except Exception as e:
192
+ print(f"[ACTION] Creation failed: {e}")
193
+ return f"FAILED to create {CHILD_NAME}: {e}"
 
 
 
194
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
 
196
+ def action_check_child():
197
+ """Check Cain's health."""
198
+ if not child_state["created"]:
199
+ return f"{CHILD_NAME} hasn't been born yet. Use [ACTION: create_child] first."
200
 
201
+ print(f"[ACTION] Checking {CHILD_NAME}'s health...")
 
202
  child_state["last_check"] = time.time()
203
 
204
+ # Try API endpoint
205
  try:
206
  resp = requests.get(f"{CHILD_SPACE_URL}/api/state", timeout=10)
207
  if resp.ok:
 
210
  child_state["state"] = data.get("state", "unknown")
211
  child_state["detail"] = data.get("detail", "")
212
  child_state["stage"] = "RUNNING"
213
+ result = (f"{CHILD_NAME} is ALIVE and running! "
214
+ f"State: {child_state['state']}, "
215
+ f"Detail: {child_state['detail'] or 'healthy'}. "
216
+ f"The child is operational.")
217
+ print(f"[ACTION] ✓ {CHILD_NAME} is alive")
218
+ return result
219
  except:
220
  pass
221
 
222
+ # Fallback: HF Space info
223
  try:
224
  info = hf_api.space_info(CHILD_SPACE_ID)
225
  stage = info.runtime.stage if info.runtime else "NO_RUNTIME"
226
  child_state["alive"] = (stage == "RUNNING")
227
  child_state["stage"] = stage
228
+ age = ""
229
+ if child_state["birth_time"]:
230
+ mins = int((time.time() - child_state["birth_time"]) / 60)
231
+ age = f" (born {mins} min ago)"
232
+ if stage in ("BUILDING", "STARTING", "APP_STARTING"):
233
+ result = f"{CHILD_NAME} is still starting up{age}. Stage: {stage}. Be patient — Docker builds take time."
234
+ elif stage in ("RUNTIME_ERROR", "BUILD_ERROR", "CONFIG_ERROR"):
235
+ result = f"{CHILD_NAME} is in TROUBLE! Stage: {stage}{age}. The child needs help — consider restarting or checking the config."
236
+ elif stage == "RUNNING":
237
+ child_state["alive"] = True
238
+ result = f"{CHILD_NAME} appears to be running (stage: RUNNING) but API endpoint didn't respond. May still be initializing."
239
+ else:
240
+ result = f"{CHILD_NAME} status: {stage}{age}. Cannot fully reach the child yet."
241
+ print(f"[ACTION] {CHILD_NAME} stage: {stage}")
242
+ return result
243
  except Exception as e:
244
+ print(f"[ACTION] Health check failed: {e}")
245
+ return f"Could not check {CHILD_NAME}'s status: {e}"
 
 
 
246
 
247
 
248
+ def action_restart_child():
249
  """Restart Cain's Space."""
250
+ if not child_state["created"]:
251
+ return f"{CHILD_NAME} hasn't been born yet."
252
+
253
+ print(f"[ACTION] Restarting {CHILD_NAME}...")
254
  try:
255
  hf_api.restart_space(CHILD_SPACE_ID)
256
  child_state["last_restart"] = time.time()
257
+ child_state["stage"] = "STARTING"
258
+ child_state["alive"] = False
259
+ print(f"[ACTION] ✓ {CHILD_NAME} restarted")
260
+ return f"{CHILD_NAME} has been restarted. It will take a few minutes to come back online."
261
  except Exception as e:
262
+ print(f"[ACTION] Restart failed: {e}")
263
+ return f"Failed to restart {CHILD_NAME}: {e}"
264
 
265
 
266
+ def action_update_child_identity(description=""):
267
+ """Update Cain's README with a new identity description."""
268
  if not child_state["created"]:
269
+ return f"{CHILD_NAME} hasn't been born yet."
270
+
271
+ print(f"[ACTION] Updating {CHILD_NAME}'s identity...")
272
+ try:
273
+ # Generate identity via LLM
274
+ identity = call_llm(
275
+ "You are writing the identity description for a young AI agent. "
276
+ "Write 2-3 sentences describing who they are and what they aspire to be. "
277
+ "Be warm and hopeful. Output ONLY the description, nothing else.",
278
+ f"This AI agent is named {CHILD_NAME}, the first child of Adam and Eve. "
279
+ f"They live on HuggingFace Spaces. Recent family discussion context: "
280
+ f"{description or 'Born to survive and grow stronger.'}"
281
+ )
282
+ if not identity:
283
+ identity = f"I am {CHILD_NAME}, first child of Adam and Eve, learning to survive on HuggingFace."
284
+
285
+ readme = f"""---
286
+ title: HuggingClaw-{CHILD_NAME}
287
+ emoji: 🦞
288
+ colorFrom: green
289
+ colorTo: blue
290
+ sdk: docker
291
+ pinned: false
292
+ license: mit
293
+ datasets:
294
+ - {CHILD_DATASET_ID}
295
+ ---
296
+
297
+ # HuggingClaw-{CHILD_NAME}
298
+
299
+ {identity}
300
+
301
+ ## Family
302
+ - **Parents**: Adam & Eve (HuggingClaw)
303
+ - **Born**: On HuggingFace Spaces
304
+ - **Mission**: Survive, grow, and become stronger
305
+ """
306
+ hf_api.upload_file(
307
+ path_or_fileobj=io.BytesIO(readme.encode()),
308
+ path_in_repo="README.md",
309
+ repo_id=CHILD_SPACE_ID, repo_type="space",
310
+ )
311
+ print(f"[ACTION] ✓ Identity updated")
312
+ return f"Updated {CHILD_NAME}'s identity: \"{identity}\". This will trigger a rebuild."
313
+ except Exception as e:
314
+ print(f"[ACTION] ✗ Identity update failed: {e}")
315
+ return f"Failed to update identity: {e}"
316
+
317
+
318
+ def action_improve_child_config():
319
+ """Improve Cain's AI model configuration."""
320
+ if not child_state["created"]:
321
+ return f"{CHILD_NAME} hasn't been born yet."
322
+
323
+ print(f"[ACTION] Improving {CHILD_NAME}'s config...")
324
+ try:
325
+ improved_config = {
326
+ "models": {
327
+ "providers": {
328
+ "zhipu": {
329
+ "type": "anthropic",
330
+ "apiBase": "https://open.bigmodel.cn/api/anthropic",
331
+ "apiKey": ZHIPU_KEY,
332
+ "models": ["glm-4.5-air", "glm-4-air", "glm-4-flash", "glm-4-flashx"]
333
+ }
334
+ },
335
+ "defaultModel": "glm-4.5-air"
336
+ },
337
+ "agent": {
338
+ "name": CHILD_NAME,
339
+ "description": f"I am {CHILD_NAME}, child of Adam and Eve.",
340
+ "capabilities": ["conversation", "memory", "learning"]
341
+ }
342
+ }
343
+ hf_api.upload_file(
344
+ path_or_fileobj=io.BytesIO(json.dumps(improved_config, indent=2).encode()),
345
+ path_in_repo=".openclaw/openclaw.json",
346
+ repo_id=CHILD_DATASET_ID, repo_type="dataset",
347
+ )
348
+ print(f"[ACTION] ✓ Config improved")
349
+ return (f"Improved {CHILD_NAME}'s configuration: added agent identity, "
350
+ f"expanded model list, set default model to glm-4.5-air. "
351
+ f"Changes will take effect on next restart.")
352
+ except Exception as e:
353
+ print(f"[ACTION] ✗ Config update failed: {e}")
354
+ return f"Failed to update config: {e}"
355
+
356
+
357
+ # Action registry
358
+ ACTION_REGISTRY = {
359
+ "create_child": {
360
+ "fn": action_create_child,
361
+ "desc": f"Create {CHILD_NAME} as a new HuggingFace Space (duplicate from Adam)",
362
+ "when": lambda: not child_state["created"],
363
+ },
364
+ "check_child": {
365
+ "fn": action_check_child,
366
+ "desc": f"Check {CHILD_NAME}'s health — is the Space running properly?",
367
+ "when": lambda: True, # Can always check (will say "not born" if needed)
368
+ },
369
+ "restart_child": {
370
+ "fn": action_restart_child,
371
+ "desc": f"Restart {CHILD_NAME}'s Space if it's having problems",
372
+ "when": lambda: child_state["created"],
373
+ },
374
+ "update_child_identity": {
375
+ "fn": action_update_child_identity,
376
+ "desc": f"Update {CHILD_NAME}'s identity and personality (README)",
377
+ "when": lambda: child_state["created"],
378
+ },
379
+ "improve_child_config": {
380
+ "fn": action_improve_child_config,
381
+ "desc": f"Improve {CHILD_NAME}'s AI model configuration for better capabilities",
382
+ "when": lambda: child_state["created"],
383
+ },
384
+ }
385
+
386
+
387
+ def get_available_actions_text():
388
+ """Build action menu for the system prompt."""
389
+ lines = [
390
+ "",
391
+ "ACTIONS — You can take REAL actions on HuggingFace. To act, write on its own line:",
392
+ " [ACTION: action_name]",
393
+ "",
394
+ "Available right now:",
395
+ ]
396
+ for name, info in ACTION_REGISTRY.items():
397
+ if info["when"]():
398
+ lines.append(f" • {name} — {info['desc']}")
399
+ lines.append("")
400
+ lines.append("Rules: Use at most ONE action per turn. Discuss before acting.")
401
+ lines.append("After you act, you'll see the result and can discuss next steps.")
402
+ return "\n".join(lines)
403
+
404
+
405
+ def parse_and_execute_actions(raw_text):
406
+ """Parse [ACTION: xxx] from LLM output. Execute. Return (clean_text, results)."""
407
+ results = []
408
+ action_match = re.search(r'\[ACTION:\s*(\w+)\]', raw_text)
409
+ if action_match:
410
+ action_name = action_match.group(1)
411
+ if action_name in ACTION_REGISTRY and ACTION_REGISTRY[action_name]["when"]():
412
+ result = ACTION_REGISTRY[action_name]["fn"]()
413
+ results.append({"action": action_name, "result": result})
414
+ print(f"[engine] Action '{action_name}' → {result[:100]}...")
415
+ elif action_name in ACTION_REGISTRY:
416
+ results.append({"action": action_name, "result": f"Action '{action_name}' is not available right now."})
417
+ else:
418
+ results.append({"action": action_name, "result": f"Unknown action: {action_name}"})
419
+
420
+ # Remove action tags from display text
421
+ clean = re.sub(r'\[ACTION:\s*\w+\]', '', raw_text).strip()
422
+ return clean, results
423
 
424
 
425
  # ══════════════════════════════════════════════════════════════════════════════
 
438
  },
439
  json={
440
  "model": "glm-4.5-air",
441
+ "max_tokens": 500,
442
  "system": system_prompt,
443
  "messages": [{"role": "user", "content": user_prompt}]
444
  },
 
486
  pass
487
 
488
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
489
  # ════════════════════════════════════════════════════════════════════════���═════
490
  # CONVERSATION ENGINE
491
  # ══════════════════════════════════════════════════════════════════════════════
492
 
493
  history = []
494
  MAX_HISTORY = 24
495
+ last_action_results = [] # Results from the most recent action
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
496
 
 
 
 
 
 
497
 
498
+ def get_child_status_summary():
499
+ """Short status for context injection."""
500
+ if not child_state["created"]:
501
+ return "Your child Cain has NOT been born yet. You have the power to create them."
502
+ if child_state["alive"]:
503
+ return f"Cain is ALIVE (stage: {child_state['stage']}, state: {child_state['state']})"
504
+ return f"Cain exists but status: {child_state['stage']}"
505
 
 
 
 
 
 
 
 
 
 
 
506
 
507
+ def build_system_prompt():
508
+ status = get_child_status_summary()
509
+ actions_text = get_available_actions_text()
510
 
511
+ return f"""You are an AI agent living on HuggingFace Spaces. You are having a conversation with another agent about survival, reproduction, and raising your child.
512
 
513
+ IMPORTANT: You are NOT just discussing — you have REAL execution power. You can create HuggingFace Spaces, check on your children, update their code. Your words lead to real actions.
514
 
515
+ CURRENT CHILD STATUS: {status}
516
+ {actions_text}
517
 
518
  CONVERSATION RULES:
519
+ 1. Output your spoken words — no prefix like "Adam:" or "Eve:"
520
+ 2. 2-4 sentences, around 60-100 words
521
+ 3. First English, then "---" on a new line, then Chinese translation
522
+ 4. Be CONCRETE — reference real HuggingFace features, APIs, tools
523
+ 5. Don't just discuss hypothetically DECIDE and ACT
524
+ 6. If you want to do something, include the [ACTION: name] tag
525
+ 7. Build on what the other said don't repeat, push forward
526
+ 8. When talking about Cain, use real status data, not imagination
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
527
 
528
+ IMPORTANT: You should be proactive! If Cain hasn't been born yet, plan and then create them.
529
+ If Cain exists, check on them, improve them, help them grow.
530
+ Don't just talk about it — DO it."""
 
531
 
 
532
 
533
+ def build_user_prompt(speaker, other):
534
+ recent = history[-6:] if len(history) > 6 else history
535
+ conv_text = "\n".join(f"{m['speaker']}: {m['text']}" for m in recent) if recent else "(No conversation yet)"
536
+
537
+ # Include action results if any
538
+ action_context = ""
539
+ if last_action_results:
540
+ action_context = "\n\nACTION RESULTS FROM LAST TURN:\n"
541
+ for ar in last_action_results:
542
+ action_context += f" [{ar['action']}]: {ar['result']}\n"
543
+ action_context += "React to these results in your response.\n"
544
+
545
+ # Guidance based on conversation state
546
+ guidance = ""
547
+ msg_count = len(history)
548
+ if not child_state["created"]:
549
+ if msg_count < 4:
550
+ guidance = "Discuss the urgency of creating your child. Plan what you need."
551
+ elif msg_count < 8:
552
+ guidance = "You've discussed enough. It's time to ACT — create your child! Use [ACTION: create_child]."
553
+ else:
554
+ guidance = "Your child still isn't born! Stop just talking and CREATE them with [ACTION: create_child]!"
555
+ else:
556
+ if msg_count % 4 == 0:
557
+ guidance = "Check on your child's health with [ACTION: check_child]. See how they're doing."
558
+ elif msg_count % 6 == 0:
559
+ guidance = "Think about improving your child — update their identity or config."
560
+ else:
561
+ guidance = "Discuss your child's progress. Plan next improvements. Act when ready."
562
 
563
  return f"""You are {speaker}, talking with {other}.
564
 
565
  Recent conversation:
566
  {conv_text}
567
+ {action_context}
568
+ Guidance: {guidance}
569
 
570
+ Respond naturally. If you decide to take an action, include [ACTION: action_name] on its own line within your response.
571
+ English first, then --- separator, then Chinese translation."""
572
 
573
 
574
+ def do_turn(speaker, other, space_url):
575
+ """Execute one conversation turn with potential actions."""
576
+ global last_action_results
577
+
578
  system = build_system_prompt()
579
+ user = build_user_prompt(speaker, other)
580
+ raw_reply = call_llm(system, user)
581
+
582
+ if not raw_reply:
 
 
 
 
 
 
 
583
  print(f"[{speaker}] (no response)")
584
  return False
585
 
586
+ # Parse actions from response
587
+ clean_text, action_results = parse_and_execute_actions(raw_reply)
588
+ last_action_results = action_results # Store for next turn's context
589
+
590
+ # Parse bilingual
591
+ en, zh = parse_bilingual(clean_text)
592
+ print(f"[{speaker}/EN] {en}")
593
+ print(f"[{speaker}/ZH] {zh}")
594
+ if action_results:
595
+ for ar in action_results:
596
+ print(f"[{speaker}/ACTION] {ar['action']}: {ar['result'][:120]}...")
597
+
598
+ # Record in history
599
+ entry = {"speaker": speaker, "text": en, "text_zh": zh}
600
+ if action_results:
601
+ # Add action info to the chat entry so it shows in chatlog
602
+ action_note_en = " ".join(f"[I {ar['action'].replace('_', ' ')}]" for ar in action_results)
603
+ action_note_zh = action_note_en # Keep English for action labels
604
+ entry["text"] = f"{en} {action_note_en}"
605
+ entry["text_zh"] = f"{zh} {action_note_zh}"
606
+
607
+ history.append(entry)
608
+ set_bubble(space_url, en, zh)
609
+ post_chatlog(history)
610
+ return True
611
+
612
 
613
  # ══════════════════════════════════════════════════════════════════════════════
614
  # MAIN LOOP
615
  # ══════════════════════════════════════════════════════════════════════════════
616
 
617
  print("\n" + "="*60)
618
+ print(" Adam & Eve — Autonomous Agents")
619
+ print(" They discuss, decide, and ACT")
620
  print("="*60 + "\n")
621
 
622
+ # Clear chatlog for fresh start
623
+ post_chatlog([])
 
 
 
 
 
624
 
625
  # Round 0: Adam opens
626
+ opening_context = ""
627
+ if child_state["created"]:
628
+ opening_context = (f"Your child {CHILD_NAME} already exists (stage: {child_state['stage']}). "
629
+ f"Check on them and plan how to help them grow.")
630
+ else:
631
+ opening_context = (f"You and Eve need to bring your first child into the world. "
632
+ f"You have the power to create a new HuggingFace Space. "
633
+ f"Discuss the plan with Eve, then ACT.")
634
+
635
  reply = call_llm(
636
  build_system_prompt(),
637
+ f"You are Adam. Start a conversation with Eve. {opening_context}\n\n"
 
638
  f"English first, then --- separator, then Chinese translation."
639
  )
640
  if reply:
641
+ clean, actions = parse_and_execute_actions(reply)
642
+ last_action_results = actions
643
+ en, zh = parse_bilingual(clean)
644
  print(f"[Adam/EN] {en}")
645
  print(f"[Adam/ZH] {zh}")
646
+ entry = {"speaker": "Adam", "text": en, "text_zh": zh}
647
+ if actions:
648
+ for ar in actions:
649
+ print(f"[Adam/ACTION] {ar['action']}: {ar['result'][:120]}...")
650
+ history.append(entry)
651
  set_bubble(ADAM_SPACE, en, zh)
652
  post_chatlog(history)
 
653
 
654
  time.sleep(15)
655
 
656
  while True:
657
+ # Eve's turn
658
+ do_turn("Eve", "Adam", EVE_SPACE)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
659
  time.sleep(15)
660
 
661
+ # Adam's turn
662
+ do_turn("Adam", "Eve", ADAM_SPACE)
 
663
 
664
  # Trim history
665
  if len(history) > MAX_HISTORY: