skip to content
Cascade (cheap → thorough → fallback)03 / 05

Should I Text Them Back?

A three-tier decision system for a one-word question.

flow graph · graphOf(text-them-back)
cascade · should-i-replycascadeShould I reply?tier · should-i-replytierGut checktier · should-i-replytierFull contextstep · ask-the-group-chatstepAsk the group chatstep · verdictstepverdictescalateescalateacceptaccept
  • calls jev
  • your code
  • leaf / emit
  • fork / join
packages/examples/src/text-them-back.ts
1/**
2 * Should I Text Them Back?
3 * Pattern: cascade. Cheap first, escalate only when unsure.
4 *
5 * Tier 1 reads only the message. If Jev is confident, we're done in one small
6 * call. If not, tier 2 re-asks with the full context (history, vibes, receipts).
7 * If *that* is still a coin flip, the fallback leaf takes over. Here it's the
8 * group chat; in production it's where you'd call an LLM or a human.
9 */
10import { cascade, chain, choice, step, tier } from "jevchain";
11import type { Example } from "./types";
13const verdict = choice("Should the recipient reply to this text message?", {
14 reply: "Replying is kind, safe and likely to lead somewhere good.",
15 "leave-on-read": "Replying would restart something unhealthy, or the message doesn't need a reply.",
16});
18const decide = cascade("should-i-reply", {
19 title: "Should I reply?",
20 tiers: [
21 tier("gut-check", { title: "Gut check", ask: verdict, minConfidence: 0.7, state: "{{input.message}}" }),
22 tier("full-context", { title: "Full context", ask: verdict, minConfidence: 0.5 }),
23 ],
24 fallback: step(
25 "ask-the-group-chat",
26 () => "Screenshot it and send it to the group chat. This is above Jev's pay grade.",
27 { title: "Ask the group chat" },
28 ),
29});
31export const textThemBack = chain(
32 "text-them-back",
33 decide,
34 step("verdict", (r) =>
35 r.resolvedBy === "fallback"
36 ? r.output
37 : r.answer.choice === "reply"
38 ? `Reply. (decided by ${r.tier}) Keep it short, you're busy and mysterious.`
39 : `Leave them on read. (decided by ${r.tier}) Put the phone in a drawer.`,
40 ),
41);
43export const example: Example = {
44 slug: "text-them-back",
45 title: "Should I Text Them Back?",
46 tagline: "A three-tier decision system for a one-word question.",
47 pattern: "Cascade (cheap → thorough → fallback)",
48 lesson:
49 "Ask the cheapest question first and only escalate when confidence is low. Each tier can see more context; the fallback can be anything, like an LLM, a human queue or your friends.",
50 chain: textThemBack,
51 file: "text-them-back.ts",
52 inputs: [
53 {
54 label: "u up?",
55 value: {
56 message: "u up?",
57 context: { theirLastMessage: "5 weeks ago", timesTheyCancelledPlans: 4, howIFeel: "I finally stopped checking my phone" },
58 },
59 },
60 {
61 label: "Birthday wishes",
62 value: {
63 message: "Happy birthday!! Hope you have the best day, we should get lunch soon 🎂",
64 context: { relationship: "old coworker", lastSpoke: "a few months ago, on good terms" },
65 },
66 },
67 {
68 label: "The ex, again",
69 value: {
70 message: "hey. saw something that reminded me of you",
71 context: { relationship: "ex", howItEnded: "they moved across the country without telling me", monthsSince: 8, howIFeel: "mostly fine?" },
72 },
73 },
74 ],
75};

api key

bring your own typesafe key, or ride the shared one (rate-limited, be nice).

shared key
checking…
your key
not set

your key stays in this browser (localStorage, jevchain.byok). it only travels to this site's /api/jev proxy in an x-typesafe-key header, which forwards it to typesafe and immediately forgets it. nothing is logged or stored server-side. requests on your own key get a much roomier rate limit.

keyboard shortcuts

fewer clicks, more chains. these work anywhere outside a text field.