Graine AI

A conversation, end to end

One conversation traced through a flow agent — from a tap in your app, or a phone call, through the welcome message, the first step, variables, a tool, a component on screen and the paths taken, to the goodbye and the record it leaves.

The other flow pages describe each part on its own. This one follows one conversation through a small flow, turn by turn, so you can see the parts work together: where the data comes from, which step runs when, what the customer hears, sees and taps, and what is left behind afterwards. Each stage links to the page that covers it in full.

The conversation starts in your app, from the assistant bar. The same flow also answers phone calls, and every stage says what differs on one.

The flow

An appointment helper: it checks the customer has a booking to move, lets them pick a new time, books it in your own system, and says goodbye.

Welcome message: "Hi {customer_name}, this is Asha from {business_name}."

[confirm]  AI reply — the first step
   ├─ AI decides: "The customer wants to move their appointment." ─► [has_booking]
   └─ AI decides: "The customer doesn't want to change anything now." ─► [goodbye]

[has_booking]  Branch — "Is there a booking to move?"
   ├─ Rule: recipient_data.open_bookings is above 0 ─► [pick_time]
   └─ Always ─► [no_booking]  Fixed line ── Always ─► [goodbye]

[pick_time]  AI reply — "Show the open times with offer_appointment_times,
             then ask which one suits them."
   └─ AI decides: "The customer has chosen a time." (collects new_time) ─► [book]

[book]  AI reply — "Confirm the appointment at {new_time}."
        Uses a tool: move_appointment
   └─ Always ─► [goodbye]

[goodbye]  AI reply — Uses a tool: End the call

Three things outside the flow take part:

What it isWhere it is set up
offer_appointment_timesA component — calendar slots drawn on the customer's screen. Its When they tap is Open a screen with the path appointments?time={id}Web components, switched on for this agent under Embed & Widgets → On screen — Components
move_appointmentOne of the agent's tools: a request to your own server with appointment_id and new_timeThe builder's Tools area — Tools, transfers and knowledge
open_screenAn in-app action your app answers by navigatingDeclared under Embed & Widgets, handled in your app — Actions

The flow's defaults give business_name the value Acme; every other variable comes from the conversation itself (The Variables panel).

How it works

Your appidentify, variables,the screen, actions— or a phone callFlow defaultsfill what theconversation lacksWelcomenot a stepconfirmAI reply · first stephas_bookingbranch · says nothingpick_timeAI reply · componentbookAI reply · your toolgoodbyeEnd the callCall Historyand your webhookno_bookingnot takenYour servermove_appointment11123The numbers are the customer's turns. Turn 1 crosses three steps; only the last one speaks.

The path this conversation takes. Dashed boxes say nothing to the customer: the branch decides within a turn, and no_booking is the path not taken.

The trace

Before anyone speaks: the data

The customer, Rohan, is on your app's appointments screen. Your app has already told the agent who he is, what he has booked and where he is:

identify({ customer_name: "Rohan" });
setVariables({ open_bookings: 1, appointment_id: "apt_3301", appointment_date: "15 October" });
useGraineScreen({ screen: "my_appointments", title: "Your appointments" });

The Android, iOS and Flutter SDKs take the same values through identify, setVariables and setScreen. When the conversation connects, these become the conversation's data: the flow fills {customer_name} from it, and rules read the same values as recipient_data.customer_name and recipient_data.open_bookings. Values travel as text, so 1 arrives as "1"; a rule still compares it as a number. The flow's own defaults fill only what is still missing — here, business_name.

On a phone call the same data comes from a campaign's columns or the variables of POST /v2/calls, and there is no screen. Variables in text

The conversation connects: the welcome message

Rohan taps the bar. The conversation opens, following the same flow as the agent's phone calls, and the welcome message plays at once: "Hi Rohan, this is Asha from Acme." It is not a step, and nothing in the flow has run yet. In a chat it arrives as text.

On a phone call it plays when the call connects. Give every variable in the welcome message a default: on a phone call it is prepared before the call connects. When the call connects

Turn 1: three steps in one turn

Rohan: "Hi — I can't make it on the 15th. Can we move my appointment?"

  1. The first step runs now, on his first words. confirm has two AI-decided paths, so the decision model reads their conditions and the conversation, and picks "The customer wants to move their appointment".
  2. The branch decides in the same turn. has_booking says nothing: its rule holds ("1" is above 0), so the call moves on to pick_time. With no booking, the Always path would have taken it to the fixed line no_booking instead.
  3. The step the call is now on replies. Rohan hears pick_time; confirm never speaks, because his first words already answered it.

The first turn · Which path the call takes

Still turn 1: a component on screen

pick_time's instructions tell the AI to show the open times. The component is a tool the AI calls by its name, offer_appointment_times: it says one is coming, the SDK draws your loader, and the calendar slots appear on Rohan's screen in your brand's design — fetched from your API at that moment if the component has an endpoint. The AI says: "I've put the next three dates on your screen — which suits you?"

The AI reply step also knows which screen Rohan is on and which component is open, and could call your in-app actions. Which tools it calls on a step it decides itself; only Uses a tool forces one.

On a phone call there is no screen and no component: write the step's instructions so they also work by voice ("…or read out two dates if they cannot see a screen"), or give each surface its own agent. On your website and in your app

Turn 2: the tap is a turn

Rohan taps Fri 17 Oct, 10:00. Three things happen:

  • The choice reaches the agent as Rohan's next turn — "Friday 17 October at 10:00 works" — and the structured answer goes to your webhook.
  • The component's When they tap → Open a screen runs your open_screen handler with appointments?time=…, and your app reports the screen it lands on.
  • pick_time's paths are checked: the decision model takes "The customer has chosen a time" and collects new_time from the conversation. From now on, text can say {new_time} and rules can test new_time.

The call moves to book, which uses a tool: on arriving it must call move_appointment, so your server receives the booking and the new time, and the AI speaks from what your server answered: "Done — you're booked for Friday 17 October at 10:00. It's on your appointments screen." Had new_time been missing, the step would have replied without calling the tool: its instructions use {new_time}, and the tool requires it.

Collecting values on the way · Make a step use a tool · When they tap

Turn 3: the goodbye ends it

Rohan: "Great, thanks." book has one path, Always, so the call moves to goodbye, which uses End the call: the AI says goodbye and the conversation hangs up once the goodbye has played. In your app the SDK reports the end of the conversation, as it does for any ending.

A step with no paths would not have ended anything: the call stays on it until the agent's call settings, in Settings › On the call, end it. How a call ends

Afterwards: what it leaves

WhereWhat you find
Call HistoryThe conversation under Rohan's name, its transcript — the welcome message, his tap as his own turn, every reply — and, for an in-app conversation, the screens he moved through and the actions the agent took with your app's answers — What lands in Call History
Execution LogsEvery turn's timing, and the connection's own rows for an in-app conversation — Execution Logs
Your serverThe move_appointment request, and the component's structured answer at your webhook
Your webhookThe call's event, as for any call — Webhooks

In your app and on a phone call

StageIn your appOn a phone call
Where the data comes fromidentify and setVariables in your appA campaign's columns, or variables on POST /v2/calls
The welcome messagePlays when the conversation connects; text in a chatPrepared before the call connects
ComponentsDrawn on screen; a tap is a turnNone — the step must work by voice
In-app actionsOffered on every AI reply stepNone
Your system moving the call—Events, with the call's execution_id
What the agent followsThe same flow, kept in step with every saveThe flow as saved

When the trace goes differently

What you seeWhy
The first step speaks even though the customer's first words answered itThe decision model did not match their words to a condition. Write the condition the way customers talk, and test by chat in the builder
The branch always takes AlwaysThe rule's field is missing or not a number. A rule on a field the conversation does not have never holds — check the variable's name, and that its value reads as a number
A {name} is silent in a replyThe variable has no value and no default, so it is left out. Set a default under Variables in the flow builder
A value your app set never arrivesA conversation carries up to 12 variables, about 1 KB in all — keep the ones the flow needs short and few
The component never appearsIt is not switched on for this agent, the step's instructions do not ask for it, or the conversation is a phone call — Is it actually on the agent?
The tap opened nothingYour app has no open_screen handler, or the action is not declared — Actions
The tool was not called on bookA variable the tool requires had no value, so the step replied without it
The call never endsNo step uses End the call (or a fixed line set to hang up still has paths out), and the agent's settings in Settings › On the call let it run on

Where next