Skip to content

Build a conditional conversation flow

Portal onlyAdvanced~25 min

Goal: build a two-stage onboarding flow where the second stage is skipped if the data it would collect already exists in memory. We'll walk it through the portal's conversation editor end-to-end, from a fresh agent to a working conditional bypass.

The skip in this walkthrough may not fire

The current chat engine evaluates only on_complete and always edges, and acts only on edges that target a conversation. The Prerequisite-skip below is an on_enter edge to a stage, so it does not fire, and neither does Step 3's stage-to-stage Next edge. This page is being checked against the engine (hadron-docs#308).

The editor steps are also out of date. The Conversation Editor has no Add edge button and no Preset field: you add a routing rule by dragging from one node to another, then set Label, Condition, Timing, Behavior and Priority in Edit routing rule. And on_complete behaves like always today, so Step 3's conditionless edge fires on the first turn where the model doesn't set next_stage, not when the stage completes; see Common edge patterns.

For the design rationale of when to use deterministic edges vs. LLM-controlled routing, read Edge conditions first. For the broader routing model, see Conversation routing.

What we're building

An onboarding conversation with two stages:

  1. collect-name — asks for the user's name and stores it in memory.name.
  2. collect-business-type — asks for industry and stores it in memory.business_type. Conditional — only entered if memory.business_type is missing.

When a returning user comes back, memory.name and memory.business_type may already be set from a prior session. The flow should glide through stages whose data is already on file and stop only at stages with missing data.

Prerequisites

  • An agent with a chatbot system memory, and a usable AI configuration on the App, the agent or the organization — see Configure your LLM provider.
  • At least one conversation node already created. If you don't have one, see Building a chatbot agent first.
  • Org admin role on the agent's organization (the conversation editor saves through admin-gated mutations).

Step 1: Open the conversation editor

  1. Open the agent detail page → Chatbot Control tab.
  2. In the conversation list, click into the conversation you'll add the flow to (or create a new one with Add conversation).
  3. The editor opens with the conversation's stages on the left and stage details on the right.

If your conversation has only the auto-generated welcome stage, that's fine — we'll add two more.

Step 2: Add the two stages

For each stage, click Add stage and fill in:

collect-name

  • Name: collect-name
  • Prompt: What's your name?
  • Extraction spec: a single field — memory.name (string, description "the user's name").

collect-business-type

  • Name: collect-business-type
  • Prompt: What kind of business are you in?
  • Extraction spec: memory.business_type (string).

Save both. The two stages now exist; what they don't have yet are the edges between them.

Step 3: Wire the linear flow

Add an edge from collect-name to collect-business-type using the Next preset:

  1. Select the collect-name stage.
  2. Click Add edge.
  3. Target: collect-business-type.
  4. Preset: Next — the editor fills in timing: on_complete and behavior: transition. Leave the condition empty (always fires).
  5. Label: "Move on after collecting name" (any text — used in the editor view, not at runtime).
  6. Save.

A user driving the bot now flows from collect-name → collect-business-type automatically when the first stage completes.

Step 4: Add the conditional bypass

Now the conditional part. We want collect-business-type to be bypassed if memory.business_type is already set. The cleanest way is a Prerequisite-style edge from collect-business-type back to itself's next stage when the data is already present — but since we only have two stages, what we really want is to skip the stage on entry: detour to wherever "after onboarding" lives, or to the conversation's terminal stage.

For this walk-through, assume a third stage welcome-back exists (or replace it with whatever stage the bot would proceed to after onboarding). Add this edge on collect-business-type:

  1. Select collect-business-type.
  2. Click Add edge.
  3. Target: welcome-back (or your post-onboarding stage).
  4. Preset: Prerequisite-skip if your editor offers it; if not, set the fields manually:
  5. Timing: on_enter
  6. Behavior: transition
  7. Condition: build it with the Condition Builder:
    • Click Add clause.
    • Field: memory.business_type.
    • Operator: exists (the editor serialises this to { "!": { "missing": ["memory.business_type"] } } — JSONLogic for "the field is present").
  8. Priority: 5 (lower priorities fire first; 5 puts this ahead of any default priority: 10 follow-on edge).
  9. Label: "Skip if business type is already set."
  10. Save.

The editor renders the condition as a tidy chip (memory.business_type · exists); behind the scenes it stores the JSONLogic expression you saw above.

Step 5: Test the flow

Test the flow in a live chat. The agent page has no chat of its own: open an App the agent is installed in and go to its Chats tab.

First-run path (data missing)

  1. In the App's Chats tab, click + New chat.
  2. The bot greets and asks for your name.
  3. Reply with a name. The bot transitions to collect-business-type (the Next edge from Step 3 fires).
  4. Reply with an industry. The bot moves on.

Confirm that a Stage transitioned toast appeared for each stage.

Returning-user path (data present)

  1. Confirm memory.business_type is set in your memory for this agent.
  2. Back in the Chats tab, click + New chat.
  3. The bot greets and asks for your name.
  4. Reply with a name. The bot transitions toward collect-business-type — and immediately fires the Prerequisite-skip edge, jumping past it to welcome-back.

You can confirm the skip in the chat surface:

  • Stage toast in the chat surface flashes the skip — there's no user-visible question for collect-business-type.

Common issues

Symptom What to check
The skip never fires; the bot still asks for business type. Expected on the current engine: it does not evaluate on_enter edges or act on edges to a stage. See the warning at the top of this page.
The skip fires every time, even on first run. The condition reads missing instead of exists. With missing, an empty memory satisfies the condition and the edge fires. Flip the operator.
The skip fires but the bot asks the question anyway. The destination stage has its own Prerequisite edge pointing back to collect-business-type. Open the destination stage in the Conversation Editor and check its outgoing edges.
Editor shows a "raw JSON view" instead of the condition builder. Someone hand-edited the JSONLogic and used an operator outside the curated UI subset (e.g. >, arithmetic, nested operators). Either edit the JSON directly or simplify.
The condition saves, but at runtime the engine fails with EDGE_CONDITION_FAILED. The condition references a variable scope outside memory.* / chat.* / agent.* / message.data.*. Check the Variable picker for the supported scopes.

What you can build from here

The Prerequisite-skip pattern in this how-to generalises:

  • Skip the welcome turn for returning users: chat.message_count > 0 skip from welcome to first real stage.
  • Branch by user type: a single memory.user_type === "founder" clause picks one of two stage targets via two edges with mirror conditions.
  • Time-bounded conversations: a now() > "2026-12-31T00:00:00Z" condition to retire a seasonal flow without deleting it.

Each stays in the same model — JSONLogic, scoped variables, edges with timing and behavior. The portal authors the curated subset; the engine evaluates the full grammar. See Edge conditions for the asymmetry and what's deferred.