Files
ai-talk-show/scripts/agent.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

120 lines
4.3 KiB
Python

#!/usr/bin/env python3
"""
Autonomous Agent — base class for Leonard and Charlie.
Each agent runs independently, reads the shared conversation log,
generates a response, and appends it to the log.
"""
import json
import time
import sys
import requests
from pathlib import Path
from datetime import datetime
# ── Config ──────────────────────────────────────────────────────────
BASE_URL = "http://100.64.0.2:39195/v1/chat/completions"
MODEL = "qwen36-27b-nvfp4-mtp-gguf"
TEMPERATURE = 0.85
PROJECT_DIR = Path(__file__).parent.parent
OUTPUT_DIR = PROJECT_DIR / "outputs"
PROMPTS_DIR = PROJECT_DIR / "prompts"
class Agent:
def __init__(self, name: str, conversation_path: Path, topic_brief: str):
self.name = name
self.conversation_path = conversation_path
self.topic_brief = topic_brief
self.system_prompt = (PROMPTS_DIR / f"{name.lower()}_system.md").read_text().strip()
self.is_opener = (name == "Leonard")
def read_conversation(self) -> list:
"""Read the current conversation log."""
if not self.conversation_path.exists():
return []
data = json.loads(self.conversation_path.read_text())
return data.get("messages", [])
def write_message(self, content: str) -> None:
"""Append a message to the conversation log."""
messages = self.read_conversation()
message = {
"agent": self.name,
"content": content,
"turn": len(messages) + 1,
"timestamp": datetime.utcnow().isoformat(),
}
messages.append(message)
self.conversation_path.write_text(json.dumps({"messages": messages}, indent=2))
def build_context(self, is_first_turn: bool) -> list:
"""Build the message context for the model call."""
conversation = self.read_conversation()
# Build conversation history
history = []
for msg in conversation:
speaker = msg["agent"]
history.append({"role": "user", "content": f"{speaker}: {msg['content']}"})
# First turn: inject topic brief
if is_first_turn and self.is_opener:
topic_msg = {
"role": "user",
"content": (
f"You're on the show now. Here's your topic:\n\n"
f"{self.topic_brief}\n\n"
"Welcome your listeners, introduce yourself and Charlie, "
"and start talking about the topic."
),
}
history.insert(0, topic_msg)
elif is_first_turn and not self.is_opener:
# Charlie's first turn after Leonard's opener
history.insert(0, {
"role": "user",
"content": "Leonard just opened the show. Respond naturally to what he said."
})
return history
def speak(self) -> dict:
"""Generate and post a response."""
messages = self.read_conversation()
is_first_turn = len(messages) == 0 if self.is_opener else (
len(messages) == 1 and messages[0]["agent"] == "Leonard"
)
history = self.build_context(is_first_turn)
# Max tokens: 250 for opener, 200 for others
max_tokens = 250 if is_first_turn and self.is_opener else 200
payload = {
"model": MODEL,
"messages": [{"role": "system", "content": self.system_prompt}] + history,
"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()
word_count = len(content.split())
turn_num = len(messages) + 1
print(f" {self.name} turn {turn_num}: {word_count} words", flush=True)
excerpt = content[:100].replace("\n", " ")
print(f"{excerpt}...", flush=True)
self.write_message(content)
return {
"agent": self.name,
"content": content,
"word_count": word_count,
"turn": turn_num,
}