Skip to Content
ToolsHealth calculator

Health calculator

The health calculator tool (ctx.HEALTH_CALCULATOR) is a built-in tool available inside any loop. It exposes deterministic, PHI-free reference math for common adult vital-sign ranges, plus a country-aware emergency-routing helper.

Use it when your loop needs to classify a reading against a published reference range and you don’t want to call out to a model. Every result includes a source or note string citing the underlying public guideline (CDC, AHA, etc.) so the loop can attribute the classification when it surfaces results to a user.

What this tool is for

  • Classifying a vital-sign reading against an adult reference range.
  • Producing a short, source-attributed note your loop can render to the user or include in a downstream message.
  • Routing a user to the right emergency number for their country when an upstream concern is flagged.

What this tool is not for

  • Not a diagnosis. Every reference range is a screening boundary — categories like high_blood_pressure_stage_2 describe the reading, not the person. Loops should pair the category with the included urgency/note string when they show it to a user.
  • Not for children. The ranges encoded here are adult reference ranges from the CDC and AHA. Pediatric ranges are different and not in scope for this tool.
  • Not a substitute for clinician review. The emergency-routing helper points to public emergency numbers and crisis lines; it does not page a clinician.

Tool API

ctx.HEALTH_CALCULATOR exposes six methods. All of them must be called inside a step.do callback — ctx only exists there. See Step context for the surrounding API.

type BmiResult = { bmi: number; category: "underweight" | "healthy_weight" | "overweight" | "obesity"; source: string; }; type BloodPressureResult = { category: | "hypertensive_crisis_range" | "high_blood_pressure_stage_2" | "high_blood_pressure_stage_1" | "elevated" | "normal"; urgency: string; source: string; }; type RestingHeartRateResult = { category: "very_low" | "low" | "typical_resting_range" | "high" | "very_high"; note: string; }; type BreathingRateResult = { category: "very_low" | "typical_adult_resting_range" | "mildly_high" | "high"; note: string; }; type Spo2Result = { category: "typical_range" | "lower_than_expected" | "urgent_range"; note: string; }; type EmergencyConcern = | "medical_emergency" | "self_harm" | "personal_safety" | "mental_health_support" | "substance_use_support"; type EmergencyRoutingResult = { country: string; emergency: string; mentalHealth?: string; personalSafety?: string; nonEmergency?: string; source: string; }; type HealthCalculatorTool = { bmi(input: { heightCm: number; weightKg: number }): Promise<BmiResult>; bloodPressure(input: { systolic: number; diastolic: number; }): Promise<BloodPressureResult>; restingHeartRate(input: { bpm: number }): Promise<RestingHeartRateResult>; breathingRate(input: { breathsPerMinute: number; }): Promise<BreathingRateResult>; oxygenSaturation(input: { percent: number }): Promise<Spo2Result>; emergencyRouting(input: { country?: string; concern: EmergencyConcern; }): Promise<EmergencyRoutingResult>; };
MethodDescription
bmiRound-to-1dp BMI with adult CDC category. Input in centimetres and kilograms.
bloodPressureClassify a systolic/diastolic pair against the AHA categories. Returns a category and an urgency string suitable to show users.
restingHeartRateClassify a resting bpm reading. Returns a category and a note covering context (athletes, symptoms, etc.).
breathingRateClassify resting breaths per minute against the adult range.
oxygenSaturationClassify an SpO2 percentage against typical, lower-than-expected, and urgent ranges.
emergencyRoutingReturn country-appropriate emergency, mental health, and personal safety numbers for the given concern.

Example: blood-pressure triage

import { Workflow } from "./loop"; export class HealthLoop extends Workflow { async run(event: HealthEvent<{ systolic: number; diastolic: number }>, step: HealthStep) { const classification = await step.do("classify-bp", async ({ ctx }) => ctx.HEALTH_CALCULATOR.bloodPressure({ systolic: event.body.systolic, diastolic: event.body.diastolic, }), ); if (classification.category === "hypertensive_crisis_range") { const routing = await step.do("escalate", async ({ ctx }) => ctx.HEALTH_CALCULATOR.emergencyRouting({ country: "South Africa", concern: "medical_emergency", }), ); return { action: "escalate", category: classification.category, urgency: classification.urgency, emergency: routing.emergency, }; } return { action: "respond", category: classification.category, urgency: classification.urgency, }; } }

PHI posture

The calculator does not read or write any user data. It accepts numeric inputs, returns categorical labels and pre-written reference strings, and emits no audit events of its own. The Loop DO still records the calling step.do row — that’s the source of truth for what your loop computed.

If your loop is calling the calculator on user-supplied vitals, the vitals themselves are PHI; treat the request body and the step return value with the same care you would any other patient data. The tool boundary itself just doesn’t widen the surface.

Country support for emergency routing

emergencyRouting currently knows about South Africa, the United Kingdom, Ireland, the United Arab Emirates, and Saudi Arabia. Unknown countries fall back to a global response that points to findahelpline.com and tells the user to call their local emergency number.

If your loop serves a country not in the list and you need specific numbers, capture the routing locally inside your loop and bypass the tool — or open an issue with the local public-resource sources you want us to add.

Last updated on