#!/usr/bin/env node import fs from "fs"; import path from "path"; const API = "http://localhost:59521"; const OUT = path.join(process.env.HOME, "Workspace/orchard9/engram/tmp"); // Re-run all 10 personas — fetch briefs and write markdown import crypto from "crypto"; const personas = [ { name: "casual-tech", messages: [ "yo have you ever messed with rust? trying to figure out if its worth learning", "yeah but like the borrow checker seems insane. is it really that bad", "hmm ok what about async stuff. heard tokio is the move", "cool cool. i mostly do typescript rn so maybe its a big jump", "bet. might just start with some cli tools first", ], }, { name: "formal-academic", messages: [ "I've been researching the implications of large language models on academic writing. What are your thoughts on the epistemological challenges they present?", "That is an interesting perspective. I am particularly concerned with the reproducibility crisis that may emerge when AI-generated text becomes indistinguishable from human-authored work.", "Indeed. My current research examines citation integrity in the context of synthetic text generation. The methodological implications are quite significant.", "I appreciate your engagement with this topic. Have you considered the role of institutional review boards in establishing guidelines for AI-assisted research?", "Precisely. I believe we need a comprehensive framework that addresses both the ethical and methodological dimensions of this paradigm shift.", ], }, { name: "emotional", messages: [ "hey... having kind of a rough day. do you ever just feel like nothing makes sense", "yeah i dont know. work stuff mostly. feeling like im not good enough", "thats actually really nice to hear. i guess i just compare myself to everyone", "youre right. i think i need to be easier on myself. its just hard sometimes", "thanks for listening. seriously. most people just say cheer up and move on", ], }, { name: "rapid-fire", messages: [ "whats the best programming language", "ok but why not python? also whats your take on AI replacing developers", "interesting. what about quantum computing? will it change everything?", "sure but when? also do you think remote work is dying? and whats the deal with web3", "lol ok last one. tabs or spaces?", ], }, { name: "deep-diver", messages: [ "been thinking a lot about consensus algorithms lately. raft vs paxos which do you think is more practical", "yeah rafts understandability is a huge win. but what about the leader bottleneck? in high-throughput scenarios it becomes a real issue", "exactly. thats why ive been looking at multi-raft where you shard the state machine. cockroachdb does this well", "the tricky part is cross-range transactions though. you need some form of 2PC or parallel commits", "right. i think the future is deterministic databases like calvin where you pre-order transactions. eliminates coordination entirely", ], }, { name: "emoji-fan", messages: [ "hiii just discovered this app and im obsessed already omg", "yes! do you like music? im really into kpop rn", "blackpink is my absolute fave but also really vibing with newjeans lately", "yesss taste! what about movies? seen anything good lately?", "ooh ill check it out! thanks bestie", ], }, { name: "skeptic", messages: [ "AI chatbots are mostly hype. Change my mind.", "Thats a surface-level argument. Most benchmarks are gamed and dont reflect real-world utility.", "Youre oversimplifying. The economic analysis doesnt support widespread adoption when you factor in inference costs and hallucination liability.", "Thats incorrect. The study youre likely referencing has significant methodological flaws.", "Ill concede narrow applications show promise. But the general intelligence narrative is fundamentally misleading.", ], }, { name: "creative-writer", messages: [ "ive been working on a short story about a lighthouse keeper who discovers the light attracts something from the deep ocean. want to hear about it?", "so the keeper notices the fish patterns change when the light hits a certain frequency. they start swimming in spirals. then one night something massive surfaces", "exactly that tension! i want the reader to feel the keepers isolation. she cant tell anyone because the coast guard would shut down the lighthouse", "ooh what if the creature communicates through bioluminescence? like its been trying to respond to the lighthouse for centuries", "yes! and the ending she has to choose between warning the world and protecting this ancient being. i think she chooses silence", ], }, { name: "shy-terse", messages: ["hi", "not much", "i guess i like reading", "fantasy mostly", "yeah sanderson is ok"], }, { name: "multi-domain", messages: [ "been learning to cook thai food this week. green curry from scratch is no joke", "oh totally different topic but have you been following the mars rover updates?", "yeah the organic compounds thing. anyway do you play any instruments? i just started guitar", "haha yeah my fingers hurt. oh hey what do you think about intermittent fasting?", "makes sense. one more random one whats your take on minimalism as a lifestyle", ], }, ]; async function parseSse(res) { const reader = res.body.getReader(); const decoder = new TextDecoder(); let buffer = "", output = ""; while (true) { const { done, value } = await reader.read(); if (done) break; buffer += decoder.decode(value, { stream: true }); const lines = buffer.split("\n"); buffer = lines.pop(); for (const line of lines) { const t = line.trim(); if (t === "data: [DONE]") continue; if (!t.startsWith("data: ")) continue; try { const d = JSON.parse(t.slice(6)); if (d.token) output += d.token; } catch {} } } return output; } function briefToMarkdown(name, personId, messages, exchanges, brief) { const lines = []; lines.push(`# ${name}`); lines.push(""); lines.push(`**personId:** \`${personId}\``); lines.push(`**interactions:** ${brief.interactionCount}`); lines.push(`**assembled:** ${brief.assemblyMs}ms`); lines.push(`**date:** ${new Date(brief.assembledAt).toISOString()}`); lines.push(""); // Conversation transcript lines.push("## Conversation"); lines.push(""); for (const ex of exchanges) { lines.push(`> **person:** ${ex.user}`); lines.push(`>`); lines.push(`> **aeries:** ${ex.assistant}`); lines.push(""); } // Style lines.push("## Style"); lines.push(""); lines.push(`| Attribute | Value |`); lines.push(`|-----------|-------|`); lines.push(`| formality | ${brief.style.formality} |`); lines.push(`| length | ${brief.style.length} |`); lines.push(`| structure | ${brief.style.structure} |`); lines.push(`| jargon | ${brief.style.usesJargon} |`); lines.push(`| emoji | ${brief.style.usesEmoji} |`); lines.push(""); // Topics lines.push("## Topics"); lines.push(""); if (brief.topics.hot.length) { lines.push("### Hot"); lines.push(""); for (const t of brief.topics.hot) { lines.push(`- **${t.topic}** (${t.domain}, ${t.specificity}) — freq ${t.frequency}${t.deepened ? " [deepened]" : ""}`); } lines.push(""); } if (brief.topics.cold.length) { lines.push("### Cold"); lines.push(""); for (const t of brief.topics.cold) { lines.push(`- ${t.topic} (${t.domain}, ${t.specificity})`); } lines.push(""); } if (brief.topics.domains.length) { lines.push(`**Domains:** ${brief.topics.domains.join(", ")}`); lines.push(""); } // Patterns lines.push("## Patterns"); lines.push(""); lines.push(`| Pattern | Value |`); lines.push(`|---------|-------|`); lines.push(`| leads conversation | ${brief.patterns.leadsConversation} |`); lines.push(`| deepens topics | ${brief.patterns.deepensTopics} |`); lines.push(`| avg sentiment | ${typeof brief.patterns.avgSentiment === "number" ? brief.patterns.avgSentiment.toFixed(3) : brief.patterns.avgSentiment} |`); lines.push(`| sentiment trend | ${brief.patterns.sentimentTrend} |`); lines.push(""); // Observations if (brief.observations.length) { lines.push("## Observations"); lines.push(""); for (const o of brief.observations) { lines.push(`- ${o}`); } lines.push(""); } // Cohort lines.push("## Cohort Priors"); lines.push(""); lines.push(`**active:** ${brief.cohortPriors.active}`); lines.push(`**weight:** ${(brief.cohortPriors.weight * 100).toFixed(0)}%`); if (brief.cohortPriors.priors.length) { lines.push(""); for (const p of brief.cohortPriors.priors) { lines.push(`- ${p}`); } } lines.push(""); // Raw JSON lines.push("## Raw Brief JSON"); lines.push(""); lines.push("```json"); lines.push(JSON.stringify(brief, null, 2)); lines.push("```"); return lines.join("\n"); } async function main() { console.log("Running 10 personas and writing briefs...\n"); for (const persona of personas) { const personId = crypto.randomUUID(); const conversationId = crypto.randomUUID(); const history = []; const exchanges = []; process.stdout.write(`[${persona.name}] `); for (let i = 0; i < persona.messages.length; i++) { const msg = persona.messages[i]; history.push({ role: "user", content: msg }); try { const res = await fetch(`${API}/api/chat`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ messages: [...history], conversationId, personId }), signal: AbortSignal.timeout(30000), }); const response = await parseSse(res); history.push({ role: "assistant", content: response }); exchanges.push({ user: msg, assistant: response }); process.stdout.write("."); } catch (err) { exchanges.push({ user: msg, assistant: `[error: ${err.message}]` }); process.stdout.write("x"); } await new Promise((r) => setTimeout(r, 800)); } // Wait for observer await new Promise((r) => setTimeout(r, 3000)); // Fetch brief let brief; try { const res = await fetch(`${API}/api/brief/${personId}`); brief = await res.json(); } catch (err) { brief = { error: err.message, style: {}, topics: { hot: [], cold: [], domains: [] }, patterns: {}, observations: [], cohortPriors: { active: false, weight: 0, priors: [] }, interactionCount: 0, assemblyMs: 0, assembledAt: Date.now(), personId }; } const md = briefToMarkdown(persona.name, personId, persona.messages, exchanges, brief); const outPath = path.join(OUT, `${persona.name}.md`); fs.writeFileSync(outPath, md); console.log(` → ${outPath}`); } console.log("\nDone."); } main().catch(console.error);