// Jev evidence battery (docs/ARCHITECTURE.md §3.3). State is the transcript alone; call metadata stays in code. export const JEV_CHAMPION = 'typesafe/jev-1.13'; export const JEV_CHALLENGER = 'typesafe/jev-1.14'; const ENDPOINT = 'https://openrouter.ai/api/v1/systemone'; const PROTECTED = ['financial', 'healthcare', 'education'] as const; export const QUESTIONS = { claims_sector: { type: 'choice', instructions: 'What kind of organization does the caller claim to be from, and what relationship does the message imply with the listener?', criteria: { financial: 'A bank, card issuer or credit union contacting the listener about an account or card they already have', healthcare: 'A pharmacy, doctor, hospital or health insurer contacting the listener about their own care or prescription', education: 'A school or school district contacting families', solicitation: 'A lender, dealer or seller offering a new loan, credit, rate, warranty, insurance or other deal', government: 'Government agency such as IRS, Social Security, police', utility_telecom: 'Utility, phone or internet provider', retail_delivery: 'Retailer or delivery company such as Amazon, UPS', other: 'Some other organization', none: 'No organization is identified', }, }, specific_detail: { type: 'noul', instructions: "Does the message contain concrete specifics a genuine organization would know, such as card or account last 4 digits, an exact amount, a merchant, a date, or the recipient's name?", }, official_channel: { type: 'noul', instructions: 'Does the message tell the listener to use an official channel they already have, such as the number on the back of their card, the official app, or the website?', }, pressure: { type: 'noul', instructions: 'Does the message use threats or urgency, such as arrest, lawsuit, account suspension, or a deadline?', }, agent_or_credentials: { type: 'noul', instructions: 'Does the message push the listener to press a key to reach a live agent, or to give or verify personal, account or payment details?', }, sales_pitch: { type: 'noul', instructions: 'Is the message offering a product, loan, rate, warranty, insurance or other deal?', }, self_assertion: { type: 'noul', instructions: "The message itself claims to be legitimate, verified, official, or 'not a scam'.", }, category: { type: 'choice', instructions: 'What kind of automated voicemail is this?', criteria: { legit_alert: 'Genuine service alert from an organization the recipient does business with (fraud alert, prescription, appointment, school notice)', scam: 'Fraud, impersonation or pretext to extract money or credentials', marketing_robocall: 'Unsolicited sales, loan, warranty or other marketing pitch', unsure: 'Too short or unclear to tell', }, }, } as const; export interface Evidence { /** "Which known script?" answer: the matched campaign id and its probability, or null for none / no question asked. */ knownScript?: { id: number; p: number } | null; sector: string; protected: number; specific: number; official: number; pressure: number; agent: number; sales: number; selfAssert: number; catLegit: number; catScam: number; catMkt: number; } export interface JevResult { evidence: Evidence; model: string; raw: unknown; } type Answers = Record; noul?: number }>; export interface KnownScript { id: number; sample: string; } const NONE = 'none'; /** The live battery plus, when junk scripts are known, one choice question listing them (docs/ARCHITECTURE.md §3.2). */ export function buildQuestions(known: KnownScript[]) { if (!known.length) return QUESTIONS; const criteria: Record = Object.fromEntries(known.map((k) => [`s${k.id}`, `Same campaign as: "${k.sample.slice(0, 300)}"`])); criteria[NONE] = 'A different message that is not one of the scripts above'; return { ...QUESTIONS, known_script: { type: 'choice', instructions: 'Is this voicemail a new recording of one of these known robocall scripts (same caller campaign, same offer or pretext, possibly reworded), or something different?', criteria, }, }; } export function toEvidence(answers: Answers): Evidence { const sector = answers.claims_sector.probabilities!; const cat = answers.category.probabilities!; const ks = answers.known_script; const knownScript = ks && ks.choice && ks.choice !== NONE ? { id: Number(ks.choice.slice(1)), p: ks.probabilities![ks.choice] ?? 0 } : null; return { knownScript, sector: answers.claims_sector.choice!, protected: PROTECTED.reduce((sum, k) => sum + (sector[k] ?? 0), 0), specific: answers.specific_detail.noul!, official: answers.official_channel.noul!, pressure: answers.pressure.noul!, agent: answers.agent_or_credentials.noul!, sales: answers.sales_pitch.noul!, selfAssert: answers.self_assertion.noul!, catLegit: cat.legit_alert ?? 0, catScam: cat.scam ?? 0, catMkt: cat.marketing_robocall ?? 0, }; } export async function askJev(transcript: string, apiKey: string, model = JEV_CHAMPION, known: KnownScript[] = []): Promise { const res = await fetch(ENDPOINT, { method: 'POST', headers: { Authorization: `Bearer ${apiKey}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ model, state: transcript, questions: buildQuestions(known) }), signal: AbortSignal.timeout(15_000), }); if (!res.ok) throw new Error(`jev ${model} ${res.status}: ${(await res.text()).slice(0, 200)}`); const body = (await res.json()) as { model: string; answers: Answers }; return { evidence: toEvidence(body.answers), model: body.model, raw: body.answers }; }