Conversation Flow

The assessment lifecycle end-to-end - phases, branching, step-back, and sequencing rules

This chapter describes the shape of a consultation from the client's point of view: which phases the user moves through, how you know what to render, when branches occur, and how the conversation ends.

The core loop

After onboarding, the entire conversation is one loop:

                ┌────────────────────────────────────────────┐
                ▼                                            │
   read response.question ──► render UI from type/messages/ │
   choices/constraints ──► user answers ──► POST /chat      │
   {type, included, excluded} ──► next response ────────────┘
                │
                └──► when conversation_details.report_possible == true
                     and no further question: GET /report

Three fields of conversation_details steer the client:

FieldMeaning
report_possibleThe final report can now be generated (GET /report).
step_back_possiblePOST /step-back is currently allowed.
conversation_endedThe conversation is over. Only the last state remains readable; a new login is required for a new assessment.

Also present: scenario (an internal state label such as CONSULTATION_QUESTIONS — useful for logging/analytics, but do not build UI logic on specific values; the set can change), progress (for a progress bar), and symptoms_summary (running lists of selected / excluded / ignored symptoms, each {cui, name} — good for a persistent "your symptoms" side panel).

There are two ways a consultation can end in a report:

  1. Consultation report — generated at the end of a completed assessment; retrieved with a separate call to GET /report once report_possible is true.
  2. Premature report — when the engine determines that no meaningful outcome can be reached with the available information, the report is returned immediately in the chat response's report field (see edge-case outcomes).

Here is a simplistic representation of how the entire flow might look, ending in a consultation report:

Phase by phase

Phase 0 — Login and consent

Covered in Authentication and Legal & Consent. Ends with an upgraded token and API-provided copy for the onboarding screen.

Phase 1 — Onboarding: POST /initial

You collect three things (using the onboarding_response questions for copy and constraints) and submit them together:

{
  "gender": "male",
  "age": 31,
  "initial_query": "earache, jaw clicks"
}

Constraints enforced by the API: age 18–125, initial_query 3–500 characters. The free-text query is spellchecked and interpreted by the medical NLU. The response is a normal chat response containing the first question.

Phase 2 — Symptom ratification

The engine extracts symptoms it recognised from the free text and asks the user to confirm them — typically a symptoms question ("Do you have any of these?") whose choices are the recognised symptoms plus closely related ones. The user's included/excluded selections seed the whole assessment.

Branching at this point:

  • Symptoms confirmed → proceeds to clarification/duration.

  • Nothing recognised, or user selects none → the flow falls back to autocomplete: an autocomplete question where the user searches for their symptom. Drive your search box with GET /symptom-search?text=... as the user types, then answer with the chosen suggestion's id (e.g. assessment_C2316035):

    { "type": "autocomplete", "included": ["assessment_C2316035"] }

    Autocomplete questions can also carry special choices — an add another symptom option and a skip option — which you send back like any other choice id.

  • Still nothing found → the engine reports that no symptom was matched and offers a restart; there may be no diagnostic report (see edge outcomes).

  • Informational intent (the user asked a general health question rather than describing symptoms) → the flow may short-circuit to an information report with articles instead of a consultation.

During ratification the user may also be offered explicit continue assessment vs add more symptoms choices — render them as ordinary choices; the ids are in the question payload.

Phase 3 — Clarification

If a confirmed symptom is ambiguous (e.g. "weakness" — muscular? general fatigue?), the engine asks one or more clarify questions, usually generic single-choice questions with alphanumeric choice ids (e.g. A290201). Answer them like any other question; several may occur in a row.

Phase 4 — Duration

A generic single-choice question asking how long the user has had the symptoms; choice ids are duration buckets (hour, day, week, month, year).

Phase 5 — Health background

A health_background multi-choice question listing pre-existing conditions and risk factors (choice ids are CUIs). Users commonly select none — send all choice ids in excluded:

{
  "type": "health_background",
  "included": [],
  "excluded": ["C0011849", "C0004096", "C0010054"]
}

Phase 6 — Diagnostic questions

The main consultation: the diagnostic engine asks a dynamic series of questions, each chosen based on the answers so far. Expect a mix of question types — symptom (single yes/no-style conditionality), symptoms (multi-select), symptoms_choose_one, and factor (influencing factors like recent injury or medication). The number of questions varies per case; the progress object is your only reliable signal of how far along the user is.

Red-flag ("rule out") questions appear here too — they look like normal questions but drive the urgent/emergency triage outcomes.

Phase 7 — Report

When report_possible is true and the flow yields no further question, call GET /report. The response contains the full structured report (Reports) and conversation_details.conversation_ended will be true: the consultation is finished, and a new one requires a new login.

Progress

"progress": { "stage": "Symptoms Assessment", "percentage": 30 }
  • percentage (0–100) drives a progress bar. It is monotonically increasing in normal flow but is an estimate — the number of remaining questions is dynamic, so don't derive "N questions left" from it.
  • stage is display-ready text for the current phase.

Step back

If conversation_details.step_back_possible is true, the user may undo the last answered question:

POST /api/v1/step-back        (empty body)

The response re-renders the previous question so the user can answer differently, and the abandoned answer is discarded. Notes:

  • One step per call; step-back is not available at the very beginning of the conversation or after the report.
  • Always gate your "Back" button on the flag from the latest response.
  • After a step-back, continue as normal: the next POST /chat answers the re-rendered question.

Re-rendering the current state: GET /chat

GET /api/v1/chat returns the current question without advancing state — use it to restore the UI after a page refresh, app resume, or navigation, instead of keeping your own copy of the last response. It is also the only call that still works after conversation_ended (returning the final state).

Sequencing rules (important)

  • The conversation is strictly sequential per token: answer the question you were last shown. There is no parallelism and no answering out of order.
  • The type you send in POST /chat must be the type of the question you are answering (the server validates answers against the current question's allowed choices and constraints — violations return 400).
  • Don't retry a POST /chat blindly on timeout: the answer may have been applied. Recover with GET /chat to see the authoritative current question, then continue from there.