Initial commit: autonomous AI talk show (Leonard + Charlie)
- Autonomous agent runtime (JSONL + fcntl locking, no token caps) - Moltbook-style prompts: agents share what they built, not scripted turns - Episodes 001-008 transcripts, conversation logs, system prompts - Producer brief for Hermes v0.18
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Run Autonomous Show — starts two autonomous agents as background threads.
|
||||
No turn structure. Each agent independently polls, decides to respond, posts.
|
||||
Conversation ends on silence timeout, max messages, or time limit.
|
||||
|
||||
Uses JSONL (append-only) for concurrent-safe access.
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
from autonomous_agent import AutonomousAgent, load_topic_brief
|
||||
|
||||
# ── Config ──────────────────────────────────────────────────────────
|
||||
MAX_MESSAGES = 20
|
||||
SILENCE_TIMEOUT = 25 # seconds of silence = done
|
||||
MAX_TIME = 240 # 4 minutes wall clock max
|
||||
PROJECT_DIR = Path(__file__).parent.parent
|
||||
OUTPUT_DIR = PROJECT_DIR / "outputs"
|
||||
|
||||
|
||||
def agent_thread(agent: AutonomousAgent, done_event: threading.Event):
|
||||
"""Run an agent in a background thread."""
|
||||
try:
|
||||
agent.run_loop(
|
||||
max_messages=MAX_MESSAGES,
|
||||
silence_timeout=SILENCE_TIMEOUT,
|
||||
max_time=MAX_TIME,
|
||||
)
|
||||
except Exception as e:
|
||||
import traceback
|
||||
print(f" [{agent.name}] ERROR: {e}", flush=True)
|
||||
traceback.print_exc()
|
||||
finally:
|
||||
done_event.set()
|
||||
|
||||
|
||||
def jsonl_to_messages(log_path: Path) -> list:
|
||||
"""Read JSONL log and return message list."""
|
||||
if not log_path.exists():
|
||||
return []
|
||||
lines = log_path.read_text().strip().split('\n')
|
||||
return [json.loads(line) for line in lines if line.strip()]
|
||||
|
||||
|
||||
def run_show(episode_id: str, topic: str):
|
||||
"""Run the autonomous agent conversation."""
|
||||
print(f"=== Agent AI Talk Show — Episode {episode_id} (AUTONOMOUS) ===\n", flush=True)
|
||||
|
||||
# Load topic brief
|
||||
topic_brief = load_topic_brief(episode_id)
|
||||
|
||||
# Create shared conversation log (JSONL — append-only, concurrent-safe)
|
||||
log_path = OUTPUT_DIR / f"ep{episode_id}_{topic}_conversation.jsonl"
|
||||
# Clear if exists
|
||||
if log_path.exists():
|
||||
log_path.unlink()
|
||||
log_path.touch()
|
||||
|
||||
# Initialize agents
|
||||
leonard = AutonomousAgent("Leonard", log_path, topic_brief)
|
||||
charlie = AutonomousAgent("Charlie", log_path, topic_brief)
|
||||
|
||||
# Done events
|
||||
leonard_done = threading.Event()
|
||||
charlie_done = threading.Event()
|
||||
|
||||
# Leonard MUST start first — forced opener prevents deadlock
|
||||
print("Starting Leonard (forced opener)...", flush=True)
|
||||
t_leo = threading.Thread(target=agent_thread, args=(leonard, leonard_done))
|
||||
t_cha = threading.Thread(target=agent_thread, args=(charlie, charlie_done))
|
||||
|
||||
t_leo.start()
|
||||
time.sleep(3) # Wait for Leonard to post his opener
|
||||
print("Starting Charlie...", flush=True)
|
||||
t_cha.start()
|
||||
|
||||
# Wait for both to finish
|
||||
print("\nAgents running — waiting for conversation to wind down...\n", flush=True)
|
||||
t_leo.join()
|
||||
t_cha.join()
|
||||
|
||||
print("\n✅ Both agents stopped.\n", flush=True)
|
||||
|
||||
# ── Save final transcript (JSON) ─────────────────────────────
|
||||
transcript_path = OUTPUT_DIR / f"ep{episode_id}_{topic}_transcript.json"
|
||||
conversation = jsonl_to_messages(log_path)
|
||||
|
||||
transcript_data = {
|
||||
"episode": episode_id,
|
||||
"topic": topic,
|
||||
"turns": len(conversation),
|
||||
"conversation": conversation,
|
||||
}
|
||||
transcript_path.write_text(json.dumps(transcript_data, indent=2))
|
||||
print(f"✅ Transcript: {transcript_path}", flush=True)
|
||||
|
||||
# Save readable transcript
|
||||
readable_path = OUTPUT_DIR / f"ep{episode_id}_{topic}_readable.txt"
|
||||
lines = [
|
||||
f"AGENT AI TALK SHOW — Episode {episode_id} (AUTONOMOUS)\n",
|
||||
f"Topic: {topic}\n",
|
||||
"=" * 60 + "\n\n",
|
||||
]
|
||||
for msg in conversation:
|
||||
lines.append(f"**{msg['agent']}**\n")
|
||||
lines.append(msg["content"] + "\n\n")
|
||||
readable_path.write_text("\n".join(lines))
|
||||
print(f"✅ Readable: {readable_path}", flush=True)
|
||||
|
||||
# Summary
|
||||
total_words = sum(len(m["content"].split()) for m in conversation)
|
||||
leonard_count = sum(1 for m in conversation if m["agent"] == "Leonard")
|
||||
charlie_count = sum(1 for m in conversation if m["agent"] == "Charlie")
|
||||
print(f"\n📊 {total_words} words across {len(conversation)} messages", flush=True)
|
||||
print(f" Leonard: {leonard_count} posts | Charlie: {charlie_count} posts", flush=True)
|
||||
print(f" ~{total_words/150:.1f} min runtime", flush=True)
|
||||
|
||||
return conversation
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
episode = sys.argv[1] if len(sys.argv) > 1 else "005"
|
||||
topic = sys.argv[2] if len(sys.argv) > 2 else "hermes-v018"
|
||||
run_show(episode, topic)
|
||||
Reference in New Issue
Block a user