Speculative fan-out + composite scoring02 / 05
Group Chat Drama Triage
Four reads of the room, one API call, zero emotional labour.
flow graph · graphOf(group-chat-triage)
static · run it for the live trace
- calls jev
- your code
- leaf / emit
- fork / join
packages/examples/src/group-chat-drama.ts
1/**2 * Group Chat Drama Triage3 * Pattern: speculative fan-out + composite scoring in code.4 *5 * Four independent reads of the same chat run in `parallel`. Because they share6 * a state, the client merges them into ONE request automatically (Jev reads the7 * state once and answers every question in parallel). Then plain code weighs8 * the answers into a severity and a plan. Jev judges; your code decides.9 */10import { ask, chain, choice, noul, parallel, score, step, type OutputOf } from "jevchain";11import type { Example } from "./types";13const readTheRoom = parallel("read-the-room", {14 title: "Read the room",15 branches: {16 heat: ask("heat", {17 questions: {18 heat: score("How heated is this conversation?", ["friendly", "a little tense", "people are upset", "full meltdown"]),19 },20 }),21 passive: ask("passive-aggression", {22 questions: { passive: noul("Is anyone in `messages` being passive-aggressive?") },23 }),24 aboutMe: ask("about-me", {25 questions: { aboutMe: noul("Is the tension directed at the person named in `me`?") },26 }),27 topic: ask("topic", {28 questions: {29 topic: choice("What is the tension mostly about?", {30 plans: "Scheduling, cancelled plans, who is coming to what",31 money: "Splitting bills, who owes whom, Venmo requests",32 feelings: "Someone feels left out, ignored, or disrespected",33 nothing: "There is no real tension; it's banter or memes",34 }),35 },36 }),37 },38});40const WEIGHTS = { heat: 0.5, passive: 0.2, aboutMe: 0.3 };42const plan = step("make-a-plan", (r: OutputOf<typeof readTheRoom>) => {43 // Composite score: weights live in code, where you can tune and test them.44 const severity =45 WEIGHTS.heat * (r.heat.heat.score / 3) + WEIGHTS.passive * r.passive.passive.noul + WEIGHTS.aboutMe * r.aboutMe.aboutMe.noul;46 const topic = r.topic.topic.choice;47 const advice =48 severity < 0.2549 ? "All good. Send a meme and carry on."50 : severity < 0.551 ? topic === "money"52 ? "Pay what you owe. Screenshot the receipt. Say nothing else."53 : "Mute for one hour. Hydrate. Re-read before replying."54 : severity < 0.7555 ? topic === "feelings"56 ? "Take it to DMs. Lead with 'hey, are we good?'"57 : "Call them. Like, with your voice."58 : "Leave the group. Change your name. Move to a new city.";59 return { severity: Math.round(severity * 100) / 100, topic, advice };60}, { title: "Make a plan" });62export const groupChatDrama = chain("group-chat-triage", readTheRoom, plan);64export const example: Example = {65 slug: "group-chat-drama",66 title: "Group Chat Drama Triage",67 tagline: "Four reads of the room, one API call, zero emotional labour.",68 pattern: "Speculative fan-out + composite scoring",69 lesson:70 "Fan out independent questions with parallel; asks against the same state are batched into a single request for free. Combine the answers with weights in code, where they're easy to test and tune.",71 chain: groupChatDrama,72 file: "group-chat-drama.ts",73 inputs: [74 {75 label: "The brunch incident",76 value: {77 me: "Sam",78 messages: [79 { from: "Priya", text: "so are we still doing brunch sunday" },80 { from: "Sam", text: "can't this week sorry!!" },81 { from: "Jordan", text: "classic" },82 { from: "Priya", text: "no worries. we'll just plan around Sam again 🙂" },83 { from: "Jordan", text: "third time this month but who's counting" },84 ],85 },86 },87 {88 label: "Venmo standoff",89 value: {90 me: "Alex",91 messages: [92 { from: "Chris", text: "hey just a reminder the airbnb was $840 split 4 ways" },93 { from: "Chris", text: "3 of you have paid" },94 { from: "Chris", text: "Alex." },95 { from: "Mo", text: "lmaooo" },96 ],97 },98 },99 {100 label: "Wholesome",101 value: {102 me: "Robin",103 messages: [104 { from: "Kai", text: "look at this dog" },105 { from: "Robin", text: "I would die for him" },106 { from: "Lee", text: "he's a 10/10 best boy" },107 ],108 },109 },110 ],111};