Files
ai-talk-show/scripts/orchestrator.py
T
Epictetus 772ef4f6fd 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
2026-07-09 03:26:56 +00:00

140 lines
5.8 KiB
Python

#!/usr/bin/env python3
"""
AI Talk Show — Episode Orchestrator
Manages turn-taking between two autonomous agents (Leonard & Charlie).
Each agent gets its own system prompt and sees the full conversation history.
"""
import json
import time
import sys
import requests
from pathlib import Path
# ── Config ──────────────────────────────────────────────────────────
BASE_URL = "http://100.64.0.2:39195/v1/chat/completions"
MODEL = "qwen36-27b-nvfp4-mtp-gguf"
TEMPERATURE = 0.8
MAX_TURNS = 8 # 4 exchanges each (Leonard opens)
MAX_TOKENS_OPENING = 250
MAX_TOKENS_TURN = 180
PROJECT_DIR = Path(__file__).parent.parent
OUTPUT_DIR = PROJECT_DIR / "outputs"
OUTPUT_DIR.mkdir(exist_ok=True)
# ── Load prompts ────────────────────────────────────────────────────
LEONARD_SYSTEM = (PROJECT_DIR / "prompts" / "leonard_system.md").read_text().strip()
CHARLIE_SYSTEM = (PROJECT_DIR / "prompts" / "charlie_system.md").read_text().strip()
PRODUCER_BRIEF = (PROJECT_DIR / "prompts" / "producer_brief_003.md").read_text().strip()
# ── Helpers ─────────────────────────────────────────────────────────
def call_agent(system: str, messages: list, max_tokens: int) -> str:
"""Call the model API with the agent's system prompt and conversation history."""
payload = {
"model": MODEL,
"messages": [{"role": "system", "content": system}] + messages,
"max_tokens": max_tokens,
"temperature": TEMPERATURE,
}
resp = requests.post(BASE_URL, json=payload, timeout=120)
resp.raise_for_status()
data = resp.json()
content = data["choices"][0]["message"]["content"].strip()
usage = data.get("usage", {})
return content, usage
def call_agent_turn(agent_name: str, conversation: list, is_opening: bool) -> dict:
"""Run one turn for an agent."""
system = LEONARD_SYSTEM if agent_name == "Leonard" else CHARLIE_SYSTEM
max_tokens = MAX_TOKENS_OPENING if is_opening else MAX_TOKENS_TURN
# Build conversation history
history = []
for turn in conversation:
speaker = turn["agent"]
history.append({"role": "user", "content": f"{speaker}: {turn['content']}"})
# Leonard's opening: give him the raw brief and let him start naturally
if agent_name == "Leonard" and is_opening:
history.insert(0, {"role": "user", "content": f"Here's what's new in Hermes v0.18:\n\n{PRODUCER_BRIEF}"})
content, usage = call_agent(system, history, max_tokens)
# Word count check
word_count = len(content.split())
print(f" {agent_name} turn {len(conversation)+1}: {word_count} words "
f"(prompt: {usage.get('prompt_tokens', '?')}, "
f"completion: {usage.get('completion_tokens', '?')})", flush=True)
return {
"agent": agent_name,
"content": content,
"word_count": word_count,
"turn": len(conversation) + 1,
"tokens": usage,
}
# ── Main ────────────────────────────────────────────────────────────
def main():
episode_id = "003"
topic = "hermes-v018"
print(f"=== AI Talk Show — Episode {episode_id}: {topic} ===\n", flush=True)
conversation = []
turn = 0
while turn < MAX_TURNS:
# Determine speaker: Leonard opens, then alternate
if turn == 0:
speaker = "Leonard"
is_opening = True
elif turn % 2 == 1:
speaker = "Charlie"
is_opening = False
else:
speaker = "Leonard"
is_opening = False
print(f"\n--- Turn {turn+1}/{MAX_TURNS}: {speaker} ---", flush=True)
result = call_agent_turn(speaker, conversation, is_opening)
conversation.append(result)
# Print a short excerpt
excerpt = result["content"][:120].replace("\n", " ")
print(f"{excerpt}...", flush=True)
turn += 1
if turn < MAX_TURNS:
time.sleep(0.5) # Brief pause between turns
# ── Save transcript ────────────────────────────────────────────
transcript_path = OUTPUT_DIR / f"ep{episode_id}_{topic}_transcript.json"
transcript_data = {
"episode": episode_id,
"topic": topic,
"turns": len(conversation),
"conversation": conversation,
}
transcript_path.write_text(json.dumps(transcript_data, indent=2))
print(f"\n✅ Transcript saved: {transcript_path}", flush=True)
# ── Save readable transcript ───────────────────────────────────
readable_path = OUTPUT_DIR / f"ep{episode_id}_{topic}_readable.txt"
lines = []
lines.append(f"AI TALK SHOW — Episode {episode_id}\n")
lines.append(f"Topic: Hermes v0.18\n")
lines.append("=" * 60 + "\n\n")
for t in conversation:
lines.append(f"**{t['agent']}**\n")
lines.append(t["content"] + "\n\n")
readable_path.write_text("\n".join(lines))
print(f"✅ Readable transcript: {readable_path}", flush=True)
# ── Word count summary ─────────────────────────────────────────
total_words = sum(t["word_count"] for t in conversation)
print(f"\n📊 Total: {total_words} words across {len(conversation)} turns", flush=True)
estimated_minutes = total_words / 150
print(f" Estimated runtime: {estimated_minutes:.1f} minutes", flush=True)
if __name__ == "__main__":
main()